Security: Inconsistent CORS implementation regarding CSS and the link element.
Reported by
1mm0rt4...@gmail.com,
Oct 17 2017
|
||||||||||
Issue descriptionVULNERABILITY DETAILS In the Google Chrome 61.0.3163.100 we found an issue with write access to cross-origin CSS rules embedded with the link element using CORS . A normal request (crossorigin attribute not set), even when answered with valid CORS headers, grants write access to cross-origin CSS rules that were embedded using the link element. Yet, when the link element is used with the crossorigin attribute set (i.e. a CORS request) write access is only granted if the server responds with valid CORS headers. Valid CORS headers mean that the Access-Control-Allow-Origin header is set to either the requesting origin or the wildcard value *. Furthermore, if the crossorigin attribute was set to use-credentials then valid CORS headers include that the Access-Control-Allow-Credentials header is set to the value true. We think that this behavior is inconsistent since either access should be granted always if access is granted in case of a non CORS request or that access should be denied in case of non CORS request and only granted if a CORS request is answered with valid CORS headers. VERSION Chrome Version: 61.0.3163.100 stable Operating System: Windows + Linux REPRODUCTION CASE We apologize that we do not provide an HTML file to reproduce the issue. To reproduce the issue please use the test cases for the link element in the framework at http://your-sop.com. To clearly view the differences displayed in the attachment visit http://your-sop.com/statsNew.php and only display differences as well as colorize. The attached files highlight the differences as they can be found in the framework.
,
Oct 17 2017
Hi, The Usenix paper is not mime, but I'm currently writing my Bachelor Thesis and the author of the paper is my supervisor. During my thesis I extended the framework. Therefore, I think it's our tool. First, no "If the HTML markup sets a |crossorigin| attribute on a LINK element pointed at a stylesheet, then that stylesheet is not applied unless the server agrees to CORS semantics using appropriate Access-Control-Allow headers." is not what I mean. Write access is defined as being able to change the embedded CSS. Therefore, I think you are right this is not a security issue. I was simply suggested to report it as an security issue to keep it from public for now. It is more like a functional issue since we can change the embedded CSS in the cross-origin case without CORS but when using CORS we can only change it if the appropriate Access-Control-Allow headers are returned. As I intended to clarify, this is simply inconsistent. It should either always allow "write access" or simple deny "write access" when not using CORS.
,
Oct 17 2017
Can you elaborate on what, specifically, you mean when you say that you can "change the embedded CSS"? A stylesheet fetched via a LINK with a |crossorigin| attribute is *ignored* unless the server sends headers that pass the "CORS check" (https://fetch.spec.whatwg.org/#concept-cors-check). Hence, there's not really anything to "change". The Fetch spec (https://fetch.spec.whatwg.org/#cors-protocol-and-credentials) calls for this behavior "If CORS flag is set and a CORS check for request and response returns failure, then return a network error." Demo: http://debugtheweb.com/test/css/cors.html In Chrome's Developer Tools console, you'll find: Access to CSS stylesheet at 'http://webdbg.com/test/css/h2.css' from origin 'http://debugtheweb.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://debugtheweb.com' is therefore not allowed access. Firefox behavior matches Chrome. Is there some reason you want to "keep it from public for now"?
,
Oct 17 2017
Ok, erm when I say change the embedded CSS is mean modifying the CSS loaded.
To verify if we can modify the CSS loaded we do something like this:
var styles = document.styleSheets[0];
styles.insertRule('h1 {color: blue !important}', 1);
var h1 = document.getElementById("h1");
var cssColor = window.getComputedStyle( h1, null).getPropertyValue("color");
if (cssColor == "rgb(0, 0, 255)") {
set(id, 'yes', "CSS is applied to element.");
} else {
set(id, 'no', "CSS is not applied to element.");
}
In short we add something to the embedded CSS.
Regarding which cases I refer. I know that the CORS behavior is actually correct as it is currently implemented.
What I wish to point out is the behavior in which Firefox disallows write access but Chrome and others allow write access.
This is basically that Chrome allows write access to cross-origin CSS even though no CORS is used at all.
I personally have no reason to keep it from public.
I simply followed the advice of my supervisor.
,
Oct 17 2017
When the stylesheet is blocked because it fails the CORS check, it is empty. JavaScript can add rules to the empty sheet (e.g. push the button on http://debugtheweb.com/test/css/corsandjs.html) although, because the sheet is empty you must adjust the insertRule call to pass 0 rather than 1. JavaScript can also add rules to a sheet that's empty because it does not exist: http://www.webdbg.com/test/css/corsand404.html
,
Oct 17 2017
Ok so it's intended to be able to add rules to a remote CSS. That means it's also intended to add rules to remote CSS that was included without the crossorigin attribute. If so then please close the ticket.
,
Oct 17 2017
Hi, after you pointed out that a link element using the crossorigin attrbiute does not load the CSS at all if it fails the CORS check I had a look at the framework again and discovered an issue with some of the link test cases leading to incorrect results. As of now I fixed this issue an will soon have it at your-sop.com. But I'd still like to point out that e.g. Firefox does not grant write access to a cross-origin CSS file that was loaded without CORS. I thought that this behavior is more in line with the idea behind CORS since CORS is supposed to lessen the restrictions employed by the SOP. Yet, I agree that it is possible to add CSS rules to an empty CSS sheet using 0 instead of 1 in the parameter. But we used 0 because we wanted only write access if the CSS was actually loaded. I hope I could make my point clear :)
,
Oct 17 2017
Edit: typo above, we used 1 because we wanted only write access if the CSS was actually loaded not 0.
,
Oct 17 2017
Indeed, Firefox refuses to permit manipulation of a cross-domain stylesheet without the |crossorigin| attribute, throwing "SecurityError: The operation is insecure." http://debugtheweb.com/test/css/corsAndJS2.html What's less clear is why this is deemed a security-sensitive operation in Firefox, as inserting a rule into the sheet does not seem to leak any information and it is allowed in Chrome, Edge, and IE.
,
Oct 18 2017
Firstly I think we shouldn't compare with Edge/IE since those two always allow read and write access to CSS regardless of the CORS settings. (even non CORS requests) I think that Firefox denies access because this is in line with normal behavior, e.g. comparing with an iframe. It's cross-origin -> you can't read or write its content.
,
Oct 18 2017
Same-Origin-Policy is more subtle than that. There are accessible (e.g. read/write and write-only) properties on cross-origin frames, for instance. If Chrome or another browser offered a direct way to read from a cross-origin file without CORS directives, that would be surprising and interesting. Writing into a stylesheet originally loaded from a cross-origin source does not seem interesting.
,
Oct 19 2017
I agree with Eric that I don't see much risk here, as it both requires script access to the page, and we're not actually exposing the CSS file's content. That said, this behavior does violate the CSSOM spec (step 1 of https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-insertrule). We should probably be calling `CSSStyleSheet::CanAccessRules()` at the top of `CSSStyleSheet::insertRule()`, and throwing a `SecurityException` accordingly. Throwing //core/css/OWNERS into `random.org` makes meade@chromium.org the lucky winner! Would you mind triaging this specific issue (and probably skimming through the rest of the `origin-clean flag` requirements at the same time)? Opening this up as a non-security, correctness bug. Thanks very much for the report!
,
Oct 19 2017
Thank you very much for your patience and sorry for any misleading or unclear explanations on my side.
,
Oct 20 2017
,
Oct 20 2017
I just want to add something regarding Comment 11: "Writing into a stylesheet originally loaded from a cross-origin source does not seem interesting." is actually just half true. You can still do "Scriptless Attacks" that are *sometimes* very similar to XSS: https://www.nds.rub.de/media/emma/veroeffentlichungen/2012/08/16/scriptlessAttacks-ccs2012.pdf
,
Oct 20 2017
"Scriptless attacks" are interesting insofar as they can trigger behaviors traditionally thought to require script. The scenario described here is to use JavaScript to manipulate a Stylesheet DOM. If the attacker already has the ability to execute script in order to manipulate the stylesheet, they've already achieved script execution and need not bother with trying to mimic script execution with a scriptless attack.
,
Oct 23 2017
,
Oct 31 2017
,
Nov 10 2017
,
Nov 21 2017
Boris noted this again in https://github.com/whatwg/html/issues/3099#issuecomment-345952988. meade@, do you think someone on the style team can take a look at aligning our cross-origin behavior with the spec (and Firefox)?
,
Nov 22 2017
Hi mkwst, I have a CL up for this (https://chromium-review.googlesource.com/c/chromium/src/+/783911), but I'm struggling a bit to update the tests...
,
Nov 23 2017
,
Nov 29 2017
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/a4ebe08c91e29140e700c7bae9b94f27a786d1ca commit a4ebe08c91e29140e700c7bae9b94f27a786d1ca Author: Eddy Mead <meade@chromium.org> Date: Wed Nov 29 04:46:24 2017 Update behavior of CSSStyleSheet to match spec for Security origin Spec is here: https://www.w3.org/TR/cssom-1/#the-cssstylesheet-interface Updated: the following methods now throw a SecurityError if the style sheet is not accessible: - cssRules() / rules() - insertRule() - deleteRule() Bug: 775525 Change-Id: I409d486df0f0fdced4684b19e3fae4c3a0ec2868 Reviewed-on: https://chromium-review.googlesource.com/783911 Commit-Queue: meade_UTC10 <meade@chromium.org> Reviewed-by: nainar <nainar@chromium.org> Cr-Commit-Position: refs/heads/master@{#520005} [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/LayoutTests/external/wpt/css/cssom/stylesheet-same-origin.sub-expected.txt [delete] https://crrev.com/447db371759f0d9638769a7b22b9560a1b2d5da5/third_party/WebKit/LayoutTests/http/tests/security/cannot-read-cssrules-expected.txt [delete] https://crrev.com/447db371759f0d9638769a7b22b9560a1b2d5da5/third_party/WebKit/LayoutTests/http/tests/security/cannot-read-cssrules-redirect-expected.txt [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/LayoutTests/http/tests/security/cannot-read-cssrules-redirect.html [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/LayoutTests/http/tests/security/cannot-read-cssrules.html [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-cssRules.php [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/Source/core/css/CSSStyleSheet.h [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/Source/core/css/CSSStyleSheet.idl [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/Source/core/css/CSSTestHelper.cpp [modify] https://crrev.com/a4ebe08c91e29140e700c7bae9b94f27a786d1ca/third_party/WebKit/Source/core/css/StyleEngineTest.cpp
,
Nov 29 2017
,
Feb 22 2018
One issue with this change is how to detect that the stylesheet isn't accessible from within the javascript. Before this change cssRules would return null and that provided a simple check for skipping sheets that either were empty or were inaccessible. There doesn't seem to be a way to check that now without comparing the href having all info about allowed origins. Is the only option to wrap the read of cssRules in a try/catch?
,
Mar 7 2018
This bugfix caused a bug in our application. Full story here: https://stackoverflow.com/questions/49161159/uncaught-domexception-failed-to-read-the-rules-property-from-cssstylesheet/49161468 Fixing the security issue is obviously top priority, but I'm wishing for a couple things that would have made this change more developer-friendly, helped us debug faster and maybe have caught the issue before it happened. 1. Advertising the change. I couldn't find mention of this change in any change logs, including the "New in Chrome 64" or "Chrome 64 deprecations" blog posts. I eventually discovered the change through a link to the Chromium commit on this Dojo Toolkit bug: https://bugs.dojotoolkit.org/ticket/19100 https://developers.google.com/web/updates/2018/01/nic64 https://developers.google.com/web/updates/2017/12/chrome-64-deprecations 2. The error message, Uncaught DOMException: Failed to read the 'rules' property from 'CSSStyleSheet' does not immediately make it clear that the problem is a CORS violation. The referenced spec (https://www.w3.org/TR/cssom-1/#the-cssstylesheet-interface) says a SecurityError exception will be thrown. I don't know how you pick an exception type in this case, but something called SecurityError might be a little clearer about what's going wrong. Just my two cents. Thanks!
,
May 17 2018
Same for us. This update affected directly UI5 framework which is using CSSStyleSheet.cssRules It happens with the scenario when we load a main page from the company's site but there is bootstrap resource loading from SAP's CDN like ui5.sap.com I wonder how many issues were caused just by this update. |
||||||||||
►
Sign in to add a comment |
||||||||||
Comment 1 by elawrence@chromium.org
, Oct 17 2017