-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Add Subresource Integrity for JS and CSS files #9933
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
Conversation
| if (item.sha512) { | ||
| itemObj.hash = item.sha512; | ||
| } else { | ||
| const hash = createHash('sha512'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we were to update tools/isobuild/bundler.js, here to also generate and store a sha512 into the manifest (thus ensuring that item.sha512 is defined above) — what would be the use-case for needing to generate this hash at run-time (on each request), as would be occurring here?
(It seems like this would be the way to go, but I'm curious if I'm missing something.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As explained below, using SHA-512 for the hash in the manifest and truncating it for filenames would be a good approach in my opinion.
| size: 24132, | ||
| hash: 'c18de19afda6e9f0db7faf3d4382a4c953cabe18' | ||
| hash: 'c18de19afda6e9f0db7faf3d4382a4c953cabe18', | ||
| sha512: 'mJ9OEOi4HbVMzqiVGOjxCiIIImgnzEg6QhorPno46yULMu/3tKmENYriasWP9RrM+wLNwlTzw6+9d+nWY9/A0A==', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps using sri would be a more appropriate name here, since the suggested algorithm might update over time? (And has already changed since when we first started discussing this — for example, SHA256 was no longer recommended by the NSA, if I recall)
| url: '/packages/templating-runtime.js?hash=c18de19afda6e9f0db7faf3d4382a4c953cabe18&v="1"', | ||
| size: 24132, | ||
| hash: 'c18de19afda6e9f0db7faf3d4382a4c953cabe18' | ||
| hash: 'c18de19afda6e9f0db7faf3d4382a4c953cabe18', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had been tempted (both today and in the past) to suggest that we switch to using a newer cipher for hash (which currently uses SHA-1, 40-bytes in length — in hex) and just use that for the SRI — relying on only a single hash! 🙌🤔
That temptation was originally based on me thinking we could go with SHA-256, which has a relatively short hexadecimal representation (64-bytes) and would still work fine as a filename (which hash is frequently used for in builds and when serving files to clients!).
Unfortunately, as hashes become more complex, they become longer and the hex representation of a SHA-512 hash would be 128-bytes — a super long filename. (Maybe too long?)
Most problematically though, SRI requires base64 encoding which, while shorter than 128-bytes for SHA-512, fails to be useful as a filename because of the base64 encoding (/, in particular), so my temptation seems to be well-prevented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I‘d recommend switching to SHA-512 and simply truncate it for the filenames. This seems to be totally fine. If more information needs to go into the filename, there’s Base58 or UNMISTAKABLE_CHARS, that would give Base55.
Recoding the hash from hex to Base64 for SRI would be trivial.
| var headSections = head.split(/<meteor-bundled-css[^<>]*>/, 2); | ||
| var cssBundle = [...(css || []).map(file => | ||
| template(' <link rel="stylesheet" type="text/css" class="__meteor-css__" href="<%- href %>">')({ | ||
| template(' <link rel="stylesheet" type="text/css" class="__meteor-css__" href="<%- href %>" integrity="sha512-<%- hash %>" crossorigin="anonymous">')({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious if this crossorigin="anonymous" might potentially cause problems for existing deployments which might necessitate the presence of user credentials (as defined here; e.g. HTTP Auth, Cookies, etc.) in order to serve the JS or CSS files (let's say the Meteor's deployment was fully behind that forced HTTP Authentication).
From what I understand, it's mandatory for crossorigin to be set for SRI to work (See 0, 1), but I'm afraid this might need to be toggleable between the valid options, anonymous and use-credentials.
Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having this configurable sounds good to me. But where would this config go ideally? Any ideas?
|
|
||
| ...(js || []).map(file => | ||
| template(' <script type="text/javascript" src="<%- src %>"></script>')({ | ||
| template(' <script type="text/javascript" src="<%- src %>" integrity="sha512-<%- hash %>" crossorigin="anonymous"></script>')({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question as above!
|
@abernix I added |
abernix
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Follow-up to #9933. As recommended by @abernix, the sha1 hash of every file is now computed from the file's sha512 hash, so we don't have to hash the entire contents of the file twice with two different algorithms. Other changes/improvements: * Invalidate the hashes when/if `File#setContents` is called. * Ignore `options.hash` and just compute hashes from actual file contents. Disagreement here would be worse than any performance benefits from precomputing the hash.
Follow-up to #9933. As recommended by @abernix, the sha1 hash of every file is now computed from the file's sha512 hash, so we don't have to hash the entire contents of the file twice with two different algorithms. Other changes/improvements: * Invalidate the hashes when/if `File#setContents` is called. * Ignore `options.hash` and just compute hashes from actual file contents. Disagreement here would be worse than any performance benefits from precomputing the hash.
Since recent changes in these packages (#9933) depend on changes to the build tool, it seems wise to tie these updates to Meteor 1.7.1.
After moving our Meteor assets out to a CDN, the Mozilla Observatory kept complaining about missing Subresouce Integrity in our JavaScript files.
This PR adds a
sha512hash to all basic Meteor files served to the client.Solves meteor/meteor-feature-requests#35.