-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CSP: form-action and redirects #8
Comments
Hrm. I think it would be inconsistent with the rest of CSP to differentiate between types of redirection, but you're right to suggest that the risk of a 302 vs 307 is substantially lower for the specific case that Setting label and milestone appropriately. |
FWIW, I think that A) enforcing form-action on http redirects doesn't offer significant security improvements (protecting against 2.3.3 below is not possible in general; protecting against 2.3.2 and 2.3.1 doesn't seem important to me). B) enforcing form-action on http redirects means that the CSP-protected page depends on what should be an implementation details of the server handling the form (i.e. a server receiving the POST data should be free to start responding with an extra, intermediate redirect hop without risking breaking some of its clients [some of whom might be using form-action CSP directive]). I think it is okay for some CSP directives to pay attention to redirects and for some directives (like form-action) to ignore redirects (i.e. only check the origin of the first http request). I think the comparison between frame-src and form-action below might make it clearer why. frame-src: 1.1. I assume that frame-src directive mainly protects the parent frame against the threat of embedding a subframe from an unintended origin. 1.2. To protect against the threat above, in theory only the final URI could be verified by CSP . 1.3. This is kind of obvious, but let me also point out that frame-src is enforced for the final URI of both server redirects and client redirects (e.g. via meta refresh and/or window.location). 1.4. frame-src doesn't look at URIs of frames opened in another window (e.g. because the anchor in a subframe had a target attribute OR was shift-clicked). Ignoring other windows seems okay, because the parent-subframe relationship is broken when opening a link in a new window (e.g. the new frame cannot try to trick the user into thinking it is a part of the parent frame's UI). OTOH, in some scenarios window.opener is still populated (e.g. when clicking an anchor with a target attribute, but not when shift-clicking an anchor) so the newly opened frame can still reach into the original parent. form-action: 2.1. I assume that form-action directive mainly protects form data against the threat of being disclosed to an unintended origin (for example when a hidden form data inside the frame contains an origin-bound secret used for authentication). 2.2. To protect against the threat above, it is important to start CSP enforcement from the very first http request (for example - verifying only the origin of the final redirect destination would be wrong, because the form data could be already disclosed to an unintended origin in the first http request). 2.3. It might be desirable to protect form data against disclosure happening after the first http request. We might want to consider the following threats (personally, I see protection against these threats as much lower priority than protection against the threat outlined in 2.2 above): 2.3.1. Threat of disclosing the form-data to intermediate server redirect destinations (e.g. disclosure to b.com if the redirect chain looks like a.com -> b.com -> c.com). We might want to consider different behavior depending on the type of a server redirect (e.g. http 307 and 308 responses preserve POST data, while other types of redirects don't). 2.3.2. Threat of disclosing the form-data to destinations reached via client redirect (e.g. redirect triggered via meta refresh and/or window.location). 2.3.3. Threat of disclosing the form-data via means other than redirection (e.g. tricking the http server from the original form action into emailing the form data to an unintended origin). 2.4. form-action needs to enforced even if the form action is opened another window (e.g. because the form element had a target attribute OR because the submit button was shift-clicked). This is because the protected resource is the form data (and the form data will be disclosed to the origin at form action URI regardless of whether the request happens in a new window or not). |
Just ran into another version of this again and thought I'd post here for some context. We recently implemented a feature on github.com that allows an organization to require external auth using SAML (in addition to their github auth) to access organization resources. The way this is implemented is that in the event that your external auth session has timed out, we show a modal dialog to let you know you need to do the external auth dance again. This modal is sensibly implemented using a partial that is fetched on demand and shoved into calling page's DOM. This makes sense since this modal might be needed on any page throughout github.com that is associated with a given organization. Once the the user clicks "auth with external provider" we do a
It is, on average, pretty tricky for a calling page to know that the endpoint it is |
To scrutinize 307 redirects with |
Lost hours on this, indeed a confusing and useless scenario. |
I've added a warning to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action about the unclear scope and inconsistent browser implementations of this directive. |
@anforowicz Re 2.1: Don't forget risks like phishing by injecting markup to assemble a fake login form that will post credentials to the attacker. |
I agree with others that Regardless of the final outcome, one of the behaviors should be explicitly defined in CSP3 (is it already somewhere?) The current situation where Chrome/Safari block redirects and Firefox does not makes deploying |
@mikewest we seem to have run into this problem in the wild with webcompat/webcompat.com#2557, ironically in a project about web compat/interop :) The error that we saw was: Is this issue at the core of this? |
No, because in that setup there should not be any redirects as I understand it. |
Reviving this bug. Would everyone be happy if I'm not an expert but I assume if a request goes through a 307 > 302 > 307 redirect chain, it will not send POST the form data to the second 307 redirect (or am I wrong?). But if the redirect chain is 307 > 307 > 307 it will send the POST form data (right?). Assuming the previous paragraph is correct, |
Restricting it to only 307/308 would completely solve it, from my perspective, as 99.9% of current redirects in applications will be 301/302 (with no CSP risk whatsoever), and whenever you do a 307/308 it will most likely be a conscious decision with known security implications - it should not be a surprise there. |
I think this would resolve the issue for us. We are now up to roughly 4-5 places in our codebase where we do a meta-redirect/JS redirect instead of a 302 just to avoid the current |
Considering that If a server has an open redirect that preserves the query string, then a 302 is as dangerous as a 307, because in that situation they both allow leaking data to third parties. So, if |
@Changaco: If you do a GET from a form to a valid |
@iquito If a server has an open redirect vulnerability then a 302 response to a form submission can result in form data being transmitted to a third party. For example if a page in the If the open redirect vulnerability is really bad and preserves the querystring, then the attacker only needs to be able to manipulate the It seems to me that the "strict" implementation of |
@Changaco If you make a GET request to Form submit to url = https://malicious.com/ Then the script makes a 302 redirect to |
@iquito The variant of open redirects in which the querystring parameters are forwarded is indeed not mentioned in the OWASP page I linked to. In that variant the vulnerable server-side script parses the In most cases involving an open redirect to forward data, the attackers can probably execute JavaScript on the vulnerable page containing the form, so they'll choose to encode the form data directly into the redirect URL instead of relying on the server to do it. |
@Changaco At that point you have multiple super heavy vulnerabilities to an extent that I don't think you will find a real world example (especially none using a CSP at the same time). Parsing the query string yourself is not a thing in most server side languages - for example in PHP you would never parse your own query string, and this kind of vulnerability could never work. You likely also need access to the HTML and possibly JS code on the page, which needs other vulnerabilities. At that point the On the other hand, the current implementation of |
I tend to agree. CSP was never meant to be a holistic solution to every single content exfiltration avenue available to an attacker. A tightly scoped |
To clarify, I also agree that it could make sense for I must also point out that even if the CSP spec is updated and browsers are modified accordingly, it could take years before the browser versions that implement the strict version of |
All the more reason to change it soon. If the spec says that form-action does not apply to 301/302 redirects, then browsers will most likely adapt fairly quickly. It might even be possible to add something like |
That's an interesting idea, but its drawback is that it sacrifices long-term cleanliness for short-term gain.
I still think that special treatment for 301/302 isn't a good idea. Instead the spec could say that only the URL of the first form submission request should be checked, not the subsequent redirects, either by default or when |
IMO the "open redirect that preserves the query string" you've raised is an example of the server shooting itself in the foot, and outside the scope of what CSP can protect it from. A 302 is not meant to preserve the original request contents. If the server deliberately re-adds those contents, then it has sabotaged itself beyond what a client-side policy should try to fix. |
I can add even one more addition, in the case of OAuth/OIDC: having to list all the domains that one might've issued an OAuth2.0 client for, in the form-action, actually also introduces an information disclosure vulnerability, in that examining the CSP at the OP can leak implicit information about what domains may be RPs. Obviously any individual RP gives this information away about itself by invoking the OAuth flow, but maybe we don't want to expose that information about all RPs at the OP side. Finally, this is a semantic point, but I don't like the idea of having to use any attribute referred to as 'unsafe' given that the OAuth2/OIDC specs say that the redirect URL MUST be validated as being that which is associated with the OAuth2.0 client itself, before redirecting the browser to it. An implementation of the OP that does not do this, has a security vulnerability. Therefore, at least in the case of OAuth2/OIDC, correctly implementing the spec is not at all something that a browser should consider 'unsafe' - it lacks context as to whether other safety measures are in place. I think 'ignore-redirect' is a nicer term. |
In Chrome, I get the following when trying to use the remote follow form: Refused to send form data to 'https://example.com/remote_follow' because it violates the following Content Security Policy directive: "form-action 'self'". It seems some browsers (but notably not Firefox) apply the form-action policy to the redirect target in addition to the initial form submission endpoint. See: w3c/webappsec-csp#8 In that thread, this workaround is suggested.
In Chrome, I get the following when trying to use the remote follow form: Refused to send form data to 'https://example.com/remote_follow' because it violates the following Content Security Policy directive: "form-action 'self'". It seems some browsers (but notably not Firefox) apply the form-action policy to the redirect target in addition to the initial form submission endpoint. See: w3c/webappsec-csp#8 In that thread, this workaround is suggested. (cherry picked from commit 9db7bdf)
Is the SSL-offloading interpreted as redirect due to the protocol change ? |
Does anyone know if there is a workaround available in Chrome to make it accept a redirect after the form? (like Firefox) My web application otherwise only works in Firefox, which would be quite annoying for some. |
@marek22k You can use a client-side redirect instead of server-side, but that involves an extra delay in redirecting and more complexity in your application. |
Mhh, that's dumb. I thought I could maybe use an additional CSP header or something like Is there any other way to allow the redirect in the CSP? I also don't quite understand why it is blocked? After all, I have allowed |
@marek22k Essentially the problem (as I understand it, I do not work for a browser vendor) is that the form-action directive is designed to prevent form submissions from being sent to random websites (e.g. because someone injected a form into your page). "But hang on, redirects don't cause the form data to be sent to the page we're redirecting to? So a redirect after a form submission can't cause form data to be sent to random websites?" They can if it's a 307 Temporary Redirect/308 Permanent Redirect status code redirect. "Well, why don't we just block form redirects to unlisted destinations on a 307/308, but allow them on 301/303 redirects?" I believe the objection here is that no other CSP directive depends on the exact response code, so this could be a great big "Gotcha!" for developers. (Much like the current behaviour). "Well... alright then, why not add a 'allow-redirects' keyword to the directive or something?" This thread has been mostly arguing about the exact syntax of such a keyword and what form it would take. e.g. Should it have the 'unsafe' keyword? If the directive isn't present, should redirects be allowed or denied? "But this issue was lodged over 6 years ago! Why haven't they agreed on a solution since then?!" Again, don't work for a browser vendor... but I get the impression that this isn't really a priority for them to solve. |
@Sora2455 Thank you for the explanation. What I don't understand now is that if it's just to stop traffic from being redirected to another website, why is the redirection to my own website also blocked? I redirect to |
I believe form-action is not usable successfully cross-browser... report-to can be used to obtain some more info from a browser. |
@marek22k That sounds like a browser error - if you can make a minimal test case, and it only happens in some browsers, then you might want to lodge a bug against that browser or browsers. |
My webapp could be used as an example: Reported on https://bugs.chromium.org/p/chromium/issues/detail?id=1464501. |
marek22k case has some other cause on its server side (protocol downgrade, so if redirects to other than self are refused, it should be blocked), as this can now be seen on its chromium bug report. So, these comments are actually irrelevant and should be hidden as "Resolved" or "Off-topic" in my opinion, included my own comment. |
The update from helmet 3 to 8 introduced default behaviour for form-action which is handled inconsistently by browsers. in chrome this prevents a redirect as a result of the POST. for full/further details see: w3c/webappsec-csp#8
The update from helmet 3 to 8 introduced default behaviour for form-action which is handled inconsistently by browsers. in chrome this prevents a redirect as a result of the POST. for full/further details see: w3c/webappsec-csp#8
The update from helmet 3 to 8 introduced default behaviour for form-action which is handled inconsistently by browsers. in chrome this prevents a redirect as a result of the POST. for full/further details see: w3c/webappsec-csp#8
From @ptoomey3 on September 23, 2015 0:12
I just wanted to open an issue to get your thoughts on
form-action
with respect to redirects. We have been working on deployingform-action
and have run into a few scenarios that all boil down to:POST
toself
One big use case of this is OAuth, where we have users submit a form to authorize access to their account. After the
POST
we redirect the user back to the OAuth application to complete the OAuth dance.However, for these kinds of scenarios to work with
form-action
we would either have to:form-action
.meta refresh
to redirect the user after authorizing (since this doesn't count as a form submit)I can see why one might want to limit method preserving redirection with a 307, but I couldn't think of much risk with allowing 302 style redirects. I guess there is some value in avoiding the redirection, though it feels somewhat orthogonal to the immediate risk associated with accidentally submitting form contents to an untrusted site. Anyway, I was just curious what your thoughts were on the topic.
/cc @mastahyeti @gregose @oreoshake
Copied from original issue: w3c/webappsec#482
The text was updated successfully, but these errors were encountered: