Subresource Integrity and Nonce Values - html

Currently, for our web application, we are generating nonce values to attach to script tags. I have recently found out about Subresource Integrity and considering that we're using a CDN (as most examples reference), I was curious if this was something my web app should use.
Is there ever a case for both nonce and integrity attributes to be used? Is one better than the other? Or, do they support multiple use cases entirely?
Thanks

They support different use cases and you can use both.
Nonce instructs the browser to execute only <script> elements which have the same nonce value set in the CSP header.
nonce-*
A cryptographic nonce (only used once) to whitelist scripts. The server must generate a unique nonce value each time it transmits a
policy. It is critical to provide a nonce that cannot be guessed as
bypassing a resource's policy is otherwise trivial. This is used in
conjunction with the script tag nonce attribute. e.g.
nonce-DhcnhD3khTMePgXwdayK9BsMqXjhguVV
So let's say your application set a Content-Security-Policy header like script-src'nonce-r4nd0m'; then the script at good.com/good.js will be executed because the nonce value is the same.
<script nonce="r4nd0m" src="//good.com/good.js">
What happens if an attacker compromises good.com and add a malicious script to good.js? That your web application still allows the execution of that script because the check is made on the nonce value not on the script content. So you need also to be sure that the content of good.js remains the same.
Here integrity attribute is involved. It implements Subresource Integrity and tells to the browser to run resources only if the computed hash matches with the one stored in the integrity attribute.
Subresource Integrity (SRI) is a security feature that enables
browsers to verify that resources they fetch (for example, from a CDN)
are delivered without unexpected manipulation. It works by allowing
you to provide a cryptographic hash that a fetched resource must
match.
So let's suppose the first time you included the script in the web app, the content of the script was safe and the integrity value was X. Then you added integrity="sha384-X" to the script element as follows.
<script src="//good.com/good.js"
integrity="sha384-X">
The attacker modifies good.js so the resulting hash of the modified script becomes Y. The browser doesn't run the script because the computed hash (Y) and the required hash (X) don't match.
I think you can combine both like this.
<script nonce="r4nd0m" integrity="sha384-X" src="//good.com/good.js">

Related

Is there a flag to disable subresource integrity checking in chromium?

We're using puppeteer and sometimes playwright to run some integration tests. We mock some of the target page's script dependencies, which causes subresource integrity hash mismatches.
Failed to find a valid digest in the 'integrity' attribute for resource 'http://localhost:3000/static/third-party/adobe-target/at-js/2.4.0-cname/at.js' with computed SHA-256 integrity '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='. The resource has been blocked."
Is there a way to disable integrity hash checking via a flag or configuration property?
No. I believe the only way is to fix or remove the integrity attribute from the source that loads the script.
Looking at the chromium (or blink) source, unless the integrity attribute is empty, the FetchManager::Loader will instantiate the SRIVerifier, whose constructor calls its OnStateChange method, where for response types of basic, cors, default (leaving out opaque responses and errors), SubresourceIntegrity::CheckSubresourceIntegrity is called. Unless the parsing of the integrity attribute fails, SubresourceIntegrity::CheckSubresourceIntegrityImpl will either successfully verify one of the digests, or it will fail with the given error message. There is no configuration option checked along this path to override a failed check.

HTTP Basic Authentication in URL supported or deprecated

On a project we spent considerable effort to work around basic authentication (because webdriver tests were depending on it, and webdriver has no api for basic authentication), and I remember basic authentication in the URL clearly not working. I.e. could not load http://username:password#url
Just google "basic authentication in url" and you will find tons of people complaining: https://medium.com/#lmakarov/say-goodbye-to-urls-with-embedded-credentials-b051f6c7b6a3
https://www.ietf.org/rfc/rfc3986.txt
Use of the format "user:password" in the userinfo field is deprecated.
Now today I told this quagmire to a friend and he said they are using http://username:password#url style basic authentication in webdriver tests without any problem.
I went in my current Chrome v71 to a demo page and to my surprise I found it indeed very well working: https://guest:guest#jigsaw.w3.org/HTTP/Basic/
How is this possible?? Are we living in parallel dimensions at the same time? Which one is true: is basic authentication using credentials in the URL supported or deprecated? (Or was this maybe added back to Chrome due to complaints of which I can't find any reference?)
Essentially, deprecated does not mean unsupported.
Which one is true: is basic authentication using credentials in the URL supported or deprecated?
The answer is yes, both are true. It is deprecated, but for the most part (anecdotally) still supported.
From the medium article:
While you would not usually have those hardcoded in a page, when you open a URL likehttps://user:pass#host and that page makes subsequent requests to resources linked via relative paths, that’s when those resources will also get the user:pass# part applied to them and banned by Chrome right there.
This means urls like <img src=./images/foo.png> but not urls like <a href=/foobar>zz</a>.
The rfc spec states:
Use of the format "user:password" in the userinfo field is
deprecated. Applications should not render as clear text any data
after the first colon (":") character found within a userinfo
subcomponent unless the data after the colon is the empty string
(indicating no password). Applications may choose to ignore or
reject such data when it is received as part of a reference and
should reject the storage of such data in unencrypted form. The
passing of authentication information in clear text has proven to be
a security risk in almost every case where it has been used.
Applications that render a URI for the sake of user feedback, such as
in graphical hypertext browsing, should render userinfo in a way that
is distinguished from the rest of a URI, when feasible. Such
rendering will assist the user in cases where the userinfo has been
misleadingly crafted to look like a trusted domain name
(Section 7.6).
So the use of user:pass#url is discouraged and backed up by specific recommendations and reasons for disabling the use. It also states that apps may opt to reject the userinfo field, but it does not say that apps must reject this.

ETags for server-side rendered pages that contain CSP nonce

I have a server-side-rendered React app and Node/Express so far were able to generate the correct, stable ETags, allowing for taking advantage of client-side caching.
Additionally, generated HTML contains fragments of render-blocking (above-the-fold) CSS and JS inlined as <script> and <style> tags for faster client-side first renders (as promoted by Google and its PageSpeed and Lighthouse tools).
Now I want to enable Content Security Policy (CSP) and I provide a nonce as an attribute to those <script> and <style> tags on every page request, to avoid unsafe-inline violations. However, ever-changing nonce makes ETags to change on every request as well. HTML is never cached and every request hits my Express server.
Is there a way to combine simultaneously:
inlined CSS and JS
CSP features (that is nonce, or similar)
ETags or alternatives
?
So far I see a contradiction between current performance vs security guidelines.
Are there equivalents to CSP nonce or can CSP nonce be provided while keeping HTML intact? Is there a way to otherwise cache pages that contain CSP nonce?
Ideally, I would like a solution to be contained within the Express server, without resorting to tinkering with my reverse proxy config, but any options are welcome.
One solution is to leave the whole content generation and caching to web application (Node in your case) and CSP nonce generation to front-end webserver (e.g. Nginx). I have implemented it with Django which does page caching with ETag, does all the Vary header logic etc and the HTML it produces contains such a static CSP nonce placeholder:
< script nonce="+++CSP_NONDE+++"> ... </script>
This placeholder is then filled in by Nginx using ngx_http_subs_filter_module:
sub_filter_once off;
sub_filter +++CSP_NONCE+++ $ssl_session_id;
add_header Content-Security-Policy "script-src 'nonce-$ssl_session_id'";
I have seen solutions using an additional Nginx module to generate a truly unique random nonce for each request but I believe it's an overkill and I'm just using TLS session identifier, which is unique per each connecting client and may be cached for some time (e.g. 10 minutes) depending on your Nginx configuration.
Just make sure the web application returns uncompressed HTML as Nginx won't be able to do string substitution.

How to cryptographically verify web page requisites?

How to cryptographically verify web page requisites in HTML?
For example, if I have some external resource like an image, a style sheet or (most importantly) a script on a (potentially untrusted) content delivery network, is it possible to force the client browser to cryptographically verify the hash of the downloaded resource before usage? Is there some HTML attribute or URL scheme for this or does one manually have to write some JavaScript to do it?
The rationale is that providing the hashes in HTML served over HTTPS provides an extra defence against compromised (or faulty) CDN-s.
Related questions on SO:
How secure are CDNs for delivering jQuery?
As of 23 June 2016 Subresource Integrity is a W3C Recommendation which allows you to do just that (draft version here). According to the Implementation Report it is already implemented in Firefox 43 and Chrome 45.
A simple example using subresource integrity would be something like:
<script src="https://example.com/example.js"
integrity="sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts="
crossorigin="anonymous"></script>
It is also possible to specify multiple algorithm-hash pairs (called metadata) in integrity field, separated by whitespace and ignoring invalid data (§3.3.3). The client is expected to filter out the strongest metadata values (§3.3.4), and compare the hash of the actual data to the hash values in set of the strongest metadata values (§3.3.5) to determine whether the resource is valid. For example:
<script src="https://example.com/example.js"
integrity="
md5-kS7IA7LOSeSlQQaNSVq1cA==
md5-pfZdWPRbfElkn7w8rizxpw==
sha256-8OTC92xYkW7CWPJGhRvqCR0U1CR6L8PhhpRGGxgW4Ts=
sha256-gx3NQgFlBqcbJoC6a/OLM/CHTcqDC7zTuJx3lGLzc38=
sha384-pp598wskwELsVAzLvb+xViyFeHA4yIV0nB5Aji1i+jZkLNAHX6NR6CLiuKWROc2d
sha384-BnYJFwkG74mEUWH4elpCm8d+RFIMDgjWWbAyaXAb8Oo//cHPOeYturyDHF/UcnUB"
crossorigin="anonymous"></script>
If the client understands SHA256 and SHA384, but not MD5, then it tokenizes the value of the integrity attribute by whitespace and throws away the md5- metadata tokens as garbage. The client then determines that the strongest hashes in the metadata are SHA384 and compares their values to the SHA384 hash of the actual data received.

What are the integrity and crossorigin attributes?

Bootstrapcdn recently changed their links. It now looks like this:
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ=="
crossorigin="anonymous">
What do the integrity and crossorigin attributes mean? How do they affect the loading of the stylesheet?
Both attributes have been added to Bootstrap CDN to implement Subresource Integrity.
Subresource Integrity defines a mechanism by which user agents may verify that a fetched resource has been delivered without unexpected manipulation Reference
Integrity attribute is to allow the browser to check the file source to ensure that the code is never loaded if the source has been manipulated.
Crossorigin attribute is present when a request is loaded using 'CORS' which is now a requirement of SRI checking when not loaded from the 'same-origin'.
More info on crossorigin
More detail on Bootstrap CDNs implementation
integrity - defines the hash value of a resource (like a checksum) that has to be matched to make the browser execute it. The hash ensures that the file was unmodified and contains expected data. This way browser will not load different (e.g. malicious) resources. Imagine a situation in which your JavaScript files were hacked on the CDN, and there was no way of knowing it. The integrity attribute prevents loading content that does not match.
Invalid SRI will be blocked (Chrome developer-tools), regardless of cross-origin. Below NON-CORS case when integrity attribute does not match:
Integrity can be calculated using: https://www.srihash.org/
Or typing into console (link):
openssl dgst -sha384 -binary FILENAME.js | openssl base64 -A
crossorigin - defines options used when the resource is loaded from a server on a different origin. (See CORS (Cross-Origin Resource Sharing) here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). It effectively changes HTTP requests sent by the browser. If the “crossorigin” attribute is added - it will result in adding origin: <ORIGIN> key-value pair into HTTP request as shown below.
crossorigin can be set to either “anonymous” or “use-credentials”. Both will result in adding origin: into the request. The latter however will ensure that credentials are checked. No crossorigin attribute in the tag will result in sending a request without origin: key-value pair.
Here is a case when requesting “use-credentials” from CDN:
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"
integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn"
crossorigin="use-credentials"></script>
A browser can cancel the request if crossorigin incorrectly set.
Links
https://www.w3.org/TR/cors/
https://www.rfc-editor.org/rfc/rfc6454
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
Blogs
https://frederik-braun.com/using-subresource-integrity.html
https://web-security.guru/en/web-security/subresource-integrity
Technically, the Integrity attribute helps with just that - it enables the proper verification of the data source. That is, it merely allows the browser to verify the numbers in the right source file with the amounts requested by the source file located on the CDN server.
Going a bit deeper, in case of the established encrypted hash value of this source and its checked compliance with a predefined value in the browser - the code executes, and the user request is successfully processed.
Crossorigin attribute helps developers optimize the rates of CDN performance, at the same time, protecting the website code from malicious scripts.
In particular, Crossorigin downloads the program code of the site in anonymous mode, without downloading cookies or performing the authentication procedure. This way, it prevents the leak of user data when you first load the site on a specific CDN server, which network fraudsters can easily replace addresses.
Source: https://yon.fun/what-is-link-integrity-and-crossorigin/