webhintio / hint

💡 A hinting engine for the web
https://webhint.io/
Apache License 2.0
3.63k stars 678 forks source link

[Bug] HTML-only headers are legitimate for non-HTML requests #3403

Open chrisgraham opened 4 years ago

chrisgraham commented 4 years ago

Using webhint.io...

I got: Response should not include unneeded 'content-security-policy' and 'x-xss-protection' headers. ...for images.

While it does use a few bytes to send these, it is a legitimate security approach. Internet Explorer will do MIME sniffing even if an accurate mime-type is sent, unless explicitly disabled. All browsers will do MIME sniffing if no mime-type is sent. Potentially mime type configuration on a server could get corrupted, or change over time.

Imagine this scenario...

Hacker uploads .webp file containing HTML code, containing JavaScript code. Server is now serving .webp file with correct mime type with no CSP headers. Website owner switches to different server configuration, without built in default mime-type for .webp Now the site has an XSS vulnerability, as browsers will sniff text/html for the .webp file.

There are many other scenarios. Specifying CSP broadly is for many people a good safety measure.

molant commented 4 years ago

Thanks @chrisgraham !

We have a few hints about headers and the panorama across browsers is changing with new standards appearing or default behavior changing. We have a few issues open where we discussed this but we had to put on hold while we did some major refactoring in other areas. That work is almost done so maybe it is time to look again into this?

Here are the list of open issues I've found:

At one moment we even talk about consolidating information into a single package. We would really appreciate your feedback on these. If you have a better idea or preference please share it.

Additionally, we've updated the reported severity for all the hints (the code should ship sometime this week, it's part of the major refactor I talked earlier). The new severities are indicated in each of the following issues:

Pinging @Malvoz just in case he has missed this issue. He's been very active in all these issues 😁

Malvoz commented 4 years ago

The issue to iterate over CSP rules is https://github.com/webhintio/hint/issues/25. But I'll answer here and we can reference or move over any conclusions as needed.

Sending headers based on media-types is an approach that is inherently error prone, for several reasons:

  1. the approach assumes usage of only some of the most popular media-types, realistically this could never cover 100% of eligible media types that developers use
  2. frame-ancestors should preferably be sent for everything (while clickjacking-protection certainly was the main motivator for the creation of this directive - as well X-Frame-Options - other things such as video/image files should also respond with this directive to prevent abuse)
  3. doesn't consider cases where Content-Type is missing
  4. doesn't cover new media-types added to the web platform

While the easiest thing to do is to just send the header for everything, the downside is, as stated already, the performance hit when doing so, especially if the header value is really large. The folks creating HTTP headers are very much taking into consideration what they'll mean in terms of header bloat, as an example, there were changes to the Sec-Fetch-* Metadata headers specification specifically to mitigate header bloat.

I'm not opposed to sending CSP in all responses, but depending on the header value size it may have a noticeable effect on performance, and also wastes user's bandwidth. However, websites that are using CSP (which according to the HTTP Archive Almanac of 2019 is only about 5%) are more likely to care about their users and thus performance optimization in other areas can be assumed.

Hopefully soon, the webappsec WG will provide some clarification on how to best approach this, (@chrisgraham I encourage you to raise your concerns) in https://github.com/w3c/webappsec/issues/520.

chrisgraham commented 4 years ago

Thanks, great reply.

From the webappsec issue, I think this is great advice:

If you think that Content-Security-Policy is irrelevant for a particular document, and/or the server hasn't been configured to have a different CSP for a given response, then I would recommend sending Content-Security-Policy: base-uri 'none'; default-src 'none'. If you are using HTTP/2 then, after the first such response, this will be compressed to almost nothing for future responses.

What I'd suggest to you guys is to not raise the error for the case of small CSP headers that are disabling JS. Continue to raise the error for non-HTML CSP headers that are too long or impotent (implies poor server configuration as per your original intent here).

molant commented 4 years ago

Thanks @chrisgraham!

I've copied your feedback in the CSP issue so we don't forget about it when we implement it.