Add Subresource Integrity (SRI) verification for remote stylesheets - #190
Open
JLLeitschuh wants to merge 3 commits into
Open
Add Subresource Integrity (SRI) verification for remote stylesheets#190JLLeitschuh wants to merge 3 commits into
JLLeitschuh wants to merge 3 commits into
Conversation
Adds an `integrity:` option to `Parser#load_uri!` that verifies a fetched remote stylesheet against a Subresource Integrity value (https://www.w3.org/TR/SRI/) before it is parsed, mirroring the `integrity` attribute browsers already support on `<link>`/`<script>` tags. Supports sha256/sha384/sha512, multiple space-separated values, and the SRI "agility" rule (only the strongest present algorithm is checked). A value naming only an unrecognized algorithm is treated as unverifiable rather than failing the fetch. On mismatch, the fetch fails the same way other remote-fetch failures already do: raises CssParser::RemoteFileError when io_exceptions is enabled, otherwise loads nothing. Useful for any caller that already knows the expected digest of a linked stylesheet and wants a stale or unexpectedly-changed response to fail closed rather than be silently parsed and applied. Co-authored-by: Claude Sonnet 5 <[email protected]>
Ruby 3.4+ removed `base64` from default gems (it's now a bundled gem that must be an explicit dependency to be resolvable). `require 'base64'` in parser.rb was relying on it still being present by default, which breaks under Ruby 4.0 CI with a LoadError. Declare it in the gemspec. Co-authored-by: Claude Sonnet 5 <[email protected]>
Contributor
Author
|
Fixed — Ruby 3.4+/4.0 removed |
Contributor
Author
|
Re: the JRuby job failure (
Flagging so it's not mistaken for a regression from this change. |
Adds a second README example showing the multi-value/multi-algorithm form of the `integrity:` option (as SRI itself allows), since the existing example only showed a single sha384 value and didn't make the "strongest algorithm wins" behavior visible without reading the implementation. Co-authored-by: Claude Sonnet 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an
integrity:option toParser#load_uri!that verifies a fetched remote stylesheet against a Subresource Integrity value before it's parsed — the same value an HTML<link integrity="...">attribute carries.sha256/sha384/sha512, multiple space-separated values in oneintegrity:string (exactly like the HTML attribute), and the spec's "agility" rule: when a value lists more than one algorithm, only the strongest present one is actually checked, and every weaker one is ignored outright — e.g.sha256-... sha384-...only checks the sha384 value. When several values are given for that same strongest algorithm (e.g. during a planned key/stylesheet rotation), matching any one of them is enough.CssParser::RemoteFileErrorwhenio_exceptionsis enabled, otherwise loads nothing.Why
Consumers of this gem that already know the expected digest of a linked stylesheet (for example, because it came from an HTML
<link integrity="...">attribute they're processing) currently have no way to askload_uri!to verify it — the fetched body is trusted unconditionally regardless of what the caller expected. This gives callers an opt-in way to fail closed instead.Testing
test/test_css_parser_integrity.rb, covering: normal pass-through when the option is omitted, all three supported algorithms, mismatch handling (with and withoutio_exceptions), the multi-algorithm "agility" rule in both directions (weaker-correct+stronger-wrong fails, weaker-wrong+stronger-correct passes), multiple acceptable values for one algorithm, and the unsupported-algorithm-is-unverifiable case.bundle exec rake test) — no behavior change whenintegrity:isn't passed.bundle exec rubocopclean on the changed files.Happy to adjust the option name/shape or add doc updates elsewhere if you'd rather it live somewhere other than
load_uri!.