Codeberg/Community
54
325
Fork
You've already forked Community
12

Content-Type Header for SVGs #220

Closed
opened 2020年07月15日 08:21:59 +02:00 by lhinderberger · 12 comments

Hello Codeberg Team,

when trying to add a logo in SVG format to the README to one of my projects here on Codeberg, I noticed that the image is not being displayed, albeit there being an img tag with the correct URL rendered.

After looking at the responses from the server, it seems that the Codeberg server returns Content-Type text/plain for SVG images, instead of image/svg+xml.

Example: lhinderberger/xeDB@9ac2454955/README.md (which loads https://codeberg.org/lhinderberger/xeDB/media/branch/master/doc/logo.svg that is being returned with Content-Type text/plain).

Thank you for providing an excellent community-driven alternative to GitHub and similar services!

EDIT: Changed URL for example, due to adding a workaround

Hello Codeberg Team, when trying to add a logo in SVG format to the README to one of my projects here on Codeberg, I noticed that the image is not being displayed, albeit there being an img tag with the correct URL rendered. After looking at the responses from the server, it seems that the Codeberg server returns Content-Type `text/plain` for SVG images, instead of `image/svg+xml`. Example: https://codeberg.org/lhinderberger/xeDB/src/commit/9ac2454955d7f36656ec1f532a339f0472806c25/README.md (which loads https://codeberg.org/lhinderberger/xeDB/media/branch/master/doc/logo.svg that is being returned with Content-Type `text/plain`). Thank you for providing an excellent community-driven alternative to GitHub and similar services! EDIT: Changed URL for example, due to adding a workaround

Thanks @hw for clarifying that this is not an issue specific to Codeberg, thus I had a look at the Gitea issue tracker.

It seems that this has been a long-time issue with Gitea, with this issue going back to 2017: https://github.com/go-gitea/gitea/issues/1095 - the issue appears to be stalling due to security concerns.

I will use a PNG version of the Logo for now as a workaround.

Thanks @hw for clarifying that this is not an issue specific to Codeberg, thus I had a look at the Gitea issue tracker. It seems that this has been a long-time issue with Gitea, with this issue going back to 2017: https://github.com/go-gitea/gitea/issues/1095 - the issue appears to be stalling due to security concerns. I will use a PNG version of the Logo for now as a workaround.
Member
Copy link

SVG as image should be safe: https://www.w3.org/wiki/SVG_Security

If you create a PR against https://codeberg.org/codeberg/gitea we can help with the arguement (if you like our support there).

cc: @6543

SVG as image should be safe: https://www.w3.org/wiki/SVG_Security If you create a PR against https://codeberg.org/codeberg/gitea we can help with the arguement (if you like our support there). cc: @6543

The main concern with including SVGs seems to be the possibility of Cross-Site-Scripting and especially the ability to steal credentials, since the SVG would be served from the same origin as the Gitea instance.

When including an SVG using an image tag, modern browsers should disallow scripts, amongst other things, as indicated by @hw's link. As far as I have understood it though, there are two main remaining risks:

  • Opening the SVGs directly (i.e. by having the user click on a harmless looking link like https://codeberg.org/lhinderberger/xeDB/media/branch/master/doc/logo.svg), which still allows scripts to be executed, unless there are Content-Security-Policy headers set (and respected by the client)
  • Older browsers or other HTTP clients that do not sandbox SVG image tags or that do not know/respect Content-Security-Policy headers

To isolate SVG images in a backwards-compatible way, one could either try to strip all unsafe elements out of the SVG image (which is hard to do right) or serve the SVGs from another (sub)domain.

The people over at Gitea have experimented with the former approach, with mixed results (https://github.com/go-gitea/gitea/pull/8024), while the latter approach isn't generalizable, because not everyone who runs a Gitea instance will be able add a proxy on another (sub)domain for serving images. In the end the issue still remains unsolved and very non-trivial to solve at that level.

But while it is hard to find a solution that works for all Gitea instances, the good news is that Codeberg could still run a fairly simple proxy server for raw / media content, that serves the contents of the repositories in their raw form to a domain like raw.codeberg.org. This approach would work fine for public repositories but not for private repositories. If we could live with that restriction, seeing that Codeberg is focused primarily on public repositories anyway, we would then only need to add the ability to Gitea to serve media content from a proxy instead of from the /someone/repo/media/... path.

If you're interested in the proxy-based solution, I could have a look into what changes to Gitea would be necessary and write a pull request.

(On a more radical note, I think that the Web needs a more lightweight and secure-by-default vector graphics format other than SVG 😉)

The main concern with including SVGs seems to be the possibility of Cross-Site-Scripting and especially the ability to steal credentials, since the SVG would be served from the same origin as the Gitea instance. When including an SVG using an image tag, modern browsers should disallow scripts, amongst other things, as indicated by @hw's link. As far as I have understood it though, there are two main remaining risks: - Opening the SVGs directly (i.e. by having the user click on a harmless looking link like https://codeberg.org/lhinderberger/xeDB/media/branch/master/doc/logo.svg), which still allows scripts to be executed, unless there are Content-Security-Policy headers set (*and* respected by the client) - Older browsers or other HTTP clients that do not sandbox SVG image tags or that do not know/respect Content-Security-Policy headers To isolate SVG images in a backwards-compatible way, one could either try to strip all unsafe elements out of the SVG image (which is hard to do right) or serve the SVGs from another (sub)domain. The people over at Gitea have experimented with the former approach, with mixed results (https://github.com/go-gitea/gitea/pull/8024), while the latter approach isn't generalizable, because not everyone who runs a Gitea instance will be able add a proxy on another (sub)domain for serving images. In the end the issue still remains unsolved and very non-trivial to solve at that level. *But* while it is hard to find a solution that works for *all* Gitea instances, the good news is that Codeberg could still run a fairly simple proxy server for raw / media content, that serves the contents of the repositories in their raw form to a domain like `raw.codeberg.org`. This approach would work fine for public repositories but not for private repositories. If we could live with that restriction, seeing that Codeberg is focused primarily on public repositories anyway, we would then only need to add the ability to Gitea to serve media content from a proxy instead of from the `/someone/repo/media/...` path. If you're interested in the proxy-based solution, I could have a look into what changes to Gitea would be necessary and write a pull request. (On a more radical note, I think that the Web needs a more lightweight and secure-by-default vector graphics format other than SVG 😉)
Member
Copy link

Alternative: always wrap SVG in image tag, even if served due to onclick-target? (Yes, right-clicking or peeling out the URL still works).

  • Older browsers or other HTTP clients that do not sandbox SVG image tags or that do not know/respect Content-Security-Policy headers

Fixing/Improving CSP headers would be a great contribution.

But while it is hard to find a solution that works for all Gitea instances, the good news is that Codeberg could still run a fairly simple proxy server for raw / media content, that serves the contents of the repositories in their raw form to a domain like raw.codeberg.org. This approach would work fine for public repositories but not for private repositories. If we could live with that restriction, seeing that Codeberg is focused primarily on public repositories anyway, we would then only need to add the ability to Gitea to serve media content from a proxy instead of from the /someone/repo/media/... path.

If you're interested in the proxy-based solution, I could have a look into what changes to Gitea would be necessary and write a pull request.

This would be great, every contribution in this area welcome.

> > - Opening the SVGs directly (i.e. by having the user click on a harmless looking link like https://codeberg.org/lhinderberger/xeDB/media/branch/master/doc/logo.svg), which still allows scripts to be executed, unless there are Content-Security-Policy headers set (*and* respected by the client) Alternative: always wrap SVG in image tag, even if served due to onclick-target? (Yes, right-clicking or peeling out the URL still works). > - Older browsers or other HTTP clients that do not sandbox SVG image tags or that do not know/respect Content-Security-Policy headers Fixing/Improving CSP headers would be a great contribution. > *But* while it is hard to find a solution that works for *all* Gitea instances, the good news is that Codeberg could still run a fairly simple proxy server for raw / media content, that serves the contents of the repositories in their raw form to a domain like `raw.codeberg.org`. This approach would work fine for public repositories but not for private repositories. If we could live with that restriction, seeing that Codeberg is focused primarily on public repositories anyway, we would then only need to add the ability to Gitea to serve media content from a proxy instead of from the `/someone/repo/media/...` path. > > If you're interested in the proxy-based solution, I could have a look into what changes to Gitea would be necessary and write a pull request. This would be great, every contribution in this area welcome.

Alternative: always wrap SVG in image tag, even if served due to onclick-target? (Yes, right-clicking or peeling out the URL still works).

It would be very interesting to find out what happens when SVGs are served as a Data-URL, regarding XSS protection across different browsers. In theory it should behave exactly as in the "regular" image tag case. If that is the case, one could fetch an SVG as text/plain and then to convert it into a image/svg+xml Data-URL using JavaScript. That way we would never directly serve untrusted SVGs and could probably limit the use of SVG in image tags to browsers of which we know it's safe.

This would be great, every contribution in this area welcome.

Well, in that case: Count me in! And while I'm at it, I think I'll sign up for Codeberg e.V. as well 😎

> Alternative: always wrap SVG in image tag, even if served due to onclick-target? (Yes, right-clicking or peeling out the URL still works). It would be very interesting to find out what happens when SVGs are served as a Data-URL, regarding XSS protection across different browsers. In theory it should behave exactly as in the "regular" image tag case. If that is the case, one could fetch an SVG as `text/plain` and then to convert it into a `image/svg+xml` Data-URL using JavaScript. That way we would never directly serve untrusted SVGs and could probably limit the use of SVG in image tags to browsers of which we know it's safe. > This would be great, every contribution in this area welcome. Well, in that case: Count me in! And while I'm at it, I think I'll sign up for Codeberg e.V. as well 😎

Browsing through the other issues: This could be solved using the same media proxy as the one needed for #196.

Browsing through the other issues: This could be solved using the same media proxy as the one needed for #196.
Member
Copy link

It would be very interesting to find out what happens when SVGs are served as a Data-URL

This sounds like a very cool idea.

> It would be very interesting to find out what happens when SVGs are served as a Data-URL This sounds like a very cool idea.

In the meantime, I've set up a local development instance of Gitea and have had a look at the code.

For the proxy solution, the core changes would need to be relatively minor: Gitea's Markdown and HTML postprocessing functions both have a section where image URLs are rewritten, which would need to be extended with the option to rewrite the URLs to a proxy.

However, in order to configure the proxy URL there would need to be changes to large parts of the Markdown and HTML postprocessing function signatures, as there is currently no centralized "DRY" way to pass down generic configuration to where we need it.

Before considering to implement the proxy solution though, we should first consider the implications with setting up such a proxy. I will add my thoughts about that to #196 and wait for definitive feedback to that before taking any further steps.

I haven't had a closer look at the Data URL approach yet other than having a brief glimpse at the frontend code of Gitea. Personally, I would strongly prefer the proxy approach, as that offers stronger isolation due to the content actually being on another origin and not requiring run-time JavaScript DOM manipulation.

In the meantime, I've set up a local development instance of Gitea and have had a look at the code. For the proxy solution, the core changes would need to be relatively minor: Gitea's Markdown and HTML postprocessing functions both have a section where image URLs are rewritten, which would need to be extended with the option to rewrite the URLs to a proxy. However, in order to configure the proxy URL there would need to be changes to large parts of the Markdown and HTML postprocessing function signatures, as there is currently no centralized "DRY" way to pass down generic configuration to where we need it. Before considering to implement the proxy solution though, we should first consider the implications with setting up such a proxy. I will add my thoughts about that to #196 and wait for definitive feedback to that before taking any further steps. I haven't had a closer look at the Data URL approach yet other than having a brief glimpse at the frontend code of Gitea. Personally, I would strongly prefer the proxy approach, as that offers stronger isolation due to the content actually being on another origin and not requiring run-time JavaScript DOM manipulation.
test repo: https://codeberg.org/6543/test-svg-mime fixed upstream: https://try.gitea.io/edgar/test-svg-mime ... added to #348
Member
Copy link

Referencing https://codeberg.org/6543/test-svg-mime:

[...] served as image/svg+xml from a different domain (raw.githubusercontent.com) [...]

We have experimental raw support implemented in Codeberg/build-deploy-gitea@5553585631 and deployed on https://codeberg-test.org, but this needs more work as it currently will bypass hidden repos (and lacks support for branches).

As I read your comment, SVG on gitea is however rendered in <img> tag and does not need content delivery from different domain to be secure?

Referencing https://codeberg.org/6543/test-svg-mime: > [...] served as image/svg+xml from a different domain (raw.githubusercontent.com) [...] We have experimental raw support implemented in https://codeberg.org/Codeberg/build-deploy-gitea/commit/55535856312a982f0cbdeb556aea3f9b563df128 and deployed on https://codeberg-test.org, but this needs more work as it currently will bypass hidden repos (and lacks support for branches). As I read your comment, SVG on gitea is however rendered in `<img>` tag and does not need content delivery from different domain to be secure?

@hw it should be save ... more infos at https://github.com/go-gitea/gitea/pull/14101 ;)

@hw it should be save ... more infos at https://github.com/go-gitea/gitea/pull/14101 ;)
Member
Copy link

This coming in 1.14?

This coming in 1.14?
Sign in to join this conversation.
No Branch/Tag specified
main
No results found.
Labels
Clear labels
accessibility

Reduces accessibility and is thus a "bug" for certain user groups on Codeberg.
bug

Something is not working the way it should. Does not concern outages.
bug
infrastructure

Errors evidently caused by infrastructure malfunctions or outages
Codeberg

This issue involves Codeberg's downstream modifications and settings and/or Codeberg's structures.
contributions welcome

Please join the discussion and consider contributing a PR!
docs

No bug, but an improvement to the docs or UI description will help
duplicate

This issue or pull request already exists
enhancement

New feature
infrastructure

Involves changes to the server setups, use `bug/infrastructure` for infrastructure-related user errors.
legal

An issue directly involving legal compliance
licence / ToS

involving questions about the ToS, especially licencing compliance
please chill
we are volunteers

Please consider editing your posts and remember that there is a human on the other side. We get that you are frustrated, but it's harder for us to help you this way.
public relations

Things related to Codeberg's external communication
question

More information is needed
question
user support

This issue contains a clearly stated problem. However, it is not clear whether we have to fix anything on Codeberg's end, but we're helping them fix it and/or find the cause.
s/Forgejo

Related to Forgejo. Please also check Forgejo's issue tracker.
s/Forgejo/migration

Migration related issues in Forgejo
s/Pages

Issues related to the Codeberg Pages feature
s/Weblate

Issue is related to the Weblate instance at https://translate.codeberg.org
s/Woodpecker

Woodpecker CI related issue
security

involves improvements to the sites security
service

Add a new service to the Codeberg ecosystem (instead of implementing into Gitea)
upstream

An open issue or pull request to an upstream repository to fix this issue (partially or completely) exists (i.e. Gitea, Forgejo, etc.)
wontfix

Codeberg's current set of contributors are not planning to spend time on delegating this issue.
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Codeberg/Community#220
Reference in a new issue
Codeberg/Community
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?