
Subresource Integrity - mastahyeti
http://githubengineering.com/subresource-integrity/
======
bsimpson
What about caching? If the HTML and the JS are both updated, but the browser
receives the new version of one and the old version of another, this will
break your page. (Since you'd now have to update the integrity attribute for
every JS change, it means you run this risk every time you update your JS.)

To be fair, running a mismatched version of the JS could already break things
if the changes are big enough, but for minor updates, the user often won't
notice the difference. Now, these cases are hard failures. That's not
necessarily a bad thing, but I wonder if there's a path here to tell the
browser "you have an old version of the content; go get the new version."

CDNs and invalidations can be tricky, and it sounds like this could lead to
things being broken more often if you're caught in the window where one piece
updates before the other.

~~~
zeveb
> What about caching? If the HTML and the JS are both updated, but the browser
> receives the new version of one and the old version of another, this will
> break your page.

Only if your page requires JavaScript to function and doesn't gracefully
degrade. None of us would ever write that sort of page, would we?

~~~
devit
It would break anyway because pages are usually designed to degrade when
JavaScript is disabled, not when the JavaScript fails to load or behaves in an
unexpected way.

For example the <noscript> tag works that way.

------
diafygi
Would love for the next generation of SRI to include signatures as an option
(e.g. integrity="ed25519-<public_key>").

Hashes means you have to specify an exact version, so there's not an easy way
to add integrity to things like Google's CDN for jQuery that has latest minor
version update links for the major API versions of jQuery.

Of course, that means also adding a signature to the payload response (maybe
an "Integrity: <hash>-<sig>" header?). So it's understandable why signatures
weren't in scope for the first release.

~~~
iancarroll
Signatures are taken care of by connecting via TLS.

If a hypothetical attack breaks TLS or you don't use it, you can just change
the public key served.

~~~
ryan-c
This is to prevent files on a 3rd party CDN from being loaded if they've been
replaced with malicious ones.

~~~
iancarroll
Ah, I see. I misunderstood. Though signatures seem to be just adding another
part in the deployment process where you update the files themselves as well
as the pages they're loaded from.

Is there any security gain from doing that?

~~~
detaro
If you include content produced by a third party (e.g. JQuery) off a CDN,
right now you can use the hash-based SRI mechanism to make sure that only the
exact file you specified can be included, otherwise the CDN could suddenly
send any compromised code. The file can't be changed, because otherwise the
hash wouldn't match.

With a signature, you could specify "include cdn.com/jquery-X if signed by the
JQuery project", so JQuery could publish security updates and those could be
rolled out to the CDNs and included in all pages automatically, without the
siteowners having to make changes (if the security fix doesn't break
compatibility).

For your own content, you'd mostly gain the convenience of not having to
update the hashes on all the pages including the resource.

~~~
infinity0
This is more convenient but less secure than a straight-up hash. If an
attacker compromises the JQuery signing key, they could still serve malicious
files. With a hash, the _authenticity_ is ONLY dependant on the TLS connection
to the main website, e.g. github.

TL;DR:

* hash: need to compromise the main website, that supplies (and authenticates) the hash

* signature by CDN: attacker can either compromise the main website OR <del>the third party CDN</del> <ins>author/signer of the third-party resource</ins>

(edit: correction as pointed out by response)

~~~
morgante
Yes, it's nominally less secure but I trust the authors of major scripts (ex.
the Facebook like button) to be able to keep their keys secure. If losing
private keys is a major security concern, then TLS is also useless.

~~~
infinity0
It's not "nominal"; losing private keys _is_ a major security concern. No,
"TLS is useless" does not follow from that - we have things like forward
secrecy which are security models specifically designed to give some
protection in the case of private key compromise.

(edit: e.g. see [https://en.greatfire.org/blog/2015/sep/popular-chinese-
ios-a...](https://en.greatfire.org/blog/2015/sep/popular-chinese-ios-apps-
compromised-unprecedented-malware-attack) just out today)

Especially in the case of a library developer, they hold the keys to many
websites, so there is extra incentive for an attacker to break that rather
than "some random guy's website". The more third-party signers you trust, the
more holes you (and your users) have.

Furthermore, you are forcing your users (who actually run this code) to place
_their_ trust in these parties too, which is not a great thing (transitive
trust) to force upon someone. (This is not the case for e.g. depending on
system libraries explicitly installed by the user.)

------
kentonv
This is nice and all, but as a security-paranoid I really wish Github would
spent some effort improving their access control model. Today, Github access
control is extremely course-grained, such that if I want to give someone
permission to merely set labels on issues, I also have to give them permission
to push arbitrary changes to the master branch. Additionally, the access
control model is weird: I can define "teams" with some set of members and some
set of repositories they can access, but the entire "team" must have the
_same_ access level to _all_ repositories they can access, making it hard to
define some repositories as being more sensitive than others. (Or, possibly,
I've misunderstood the model, but if so that's its own problem.)

This matters: If someone wants to hack my company, they're not going to do it
by hacking Github's CDN. They're going to do it by targeting particular
employees -- probably focusing on those who have the least security
experience. To reduce risk, I need to give each team member the least
authority they need to do their job. Github is making it really hard for me to
do that; I tend to have to give "admin" rights to everyone. :(

------
bosdev
I really wish browsers could leverage this for caching across origins. If my
copy of jQuery has the same SHA256 as another file the user has already
downloaded, there's no need to load it again

~~~
duskwuff
There's subtle, dangerous ways this can be exploited. (Short version: It'd
make SRI usable as an oracle to confirm or deny guesses for the content of a
cross-domain resource.)

~~~
skrebbel
How is that dangerous?

~~~
ihsw
It leaks private user info -- a malicious server could include a JS file
confirmed to be highly sensitive/top secret, and measure whether the client
already has that cached. If so then the user is confirmed a sensitive target.

~~~
realusername
you could just add a new public=true option to counter this. I think you can
even already check that with an iframe (or js head inject & timing) anyway, no
need for CSP for that.

~~~
riking
Or require crossorigin="anonymous", maybe in combination with Cache-Control:
public.

------
dccoolgai
This is one of the best additions to the Web Platform as of late IMHO. Great
if you run an operation with a lot of third party code coming in from sources
that you don't control - even beyond the security concerns for just "keeping
them honest" about the scripts they run on your page. I hope it gets adopted
by all browser vendors soon.

------
adrianmacneil
This looks like a fantastic technology to protect against maliciously injected
javascript. Great to see GitHub leading the charge here and taking their
security seriously.

~~~
ihsw
As mentioned in the article, they were victims of such an attack.

Frankly I'm relieved to see that browser vendors and leading tech firms are
maintaining control of the situation and protecting users, even if driven by
self-interest.

------
cbr

        Widespread adoption of Subresource Integrity could
        have largely prevented the Great Cannon attack
        earlier this year.
    

Sorry, it wouldn't have. From the CitizenLab report [1] on the Great Cannon
attacks:

    
    
        In the attack on GitHub and GreatFire.org, the GC
        intercepted traffic sent to Baidu infrastructure
        servers that host commonly used analytics, social,
        or advertising scripts.  If the GC saw a request
        for certain Javascript files on one of these servers,
        it appeared to probabilistically take one of two
        actions: it either passed the request onto Baidu’s
        servers unmolested (roughly 98.25% of the time),
        or it dropped the request before it reached Baidu
        and instead sent a malicious script back to the
        requesting user (roughly 1.75% of the time).  In
        this case, the requesting user is an individual
        outside China browsing a website making use of a
        Baidu infrastructure server (e.g., a website with
        ads served by Baidu’s ad network).  The malicious
        script enlisted the requesting user as an unwitting
        participant in the DDoS attack against GreatFire.org
        and GitHub.
    

So the idea is someone runs a site with:

    
    
        <script src="http://baidu.com/ads.js">
    

When visitors request these scripts the request passes through the "Great
Cannon" which 1.75% of the time serves a different script instead. That
malicious script makes lots of requests to the victim sites, and they're
overloaded.

To prevent this sort of attack with SRI you would need to change your page to
look like:

    
    
        <script src="http://baidu.com/ads.js"
                integrity="hash of the real ads.js">
    

The problem is, Baidu isn't going to be willing to commit to always serving
the same ads js: they need to be able to make upgrades.

SRI is useful in the case where the entity producing the html is referencing
js that they've uploaded to a third party CDN or js where they choose what
version to run, but not in the normal "include a snippet and we'll do stuff to
your page" model.

(To block the Great Cannon there, what would have worked would be moving the
js serving to HTTPS.)

[1] [https://citizenlab.org/2015/04/chinas-great-
cannon/](https://citizenlab.org/2015/04/chinas-great-cannon/)

------
bhouston
Couldn't the great chinese firewall just intercept Github.com's HTML page as
well and change the subresource integrity hashes? I thought that the Great
Chinese Firewall already has the ability to penetrate SSL connections via some
means.

~~~
nailer
The Great Firewall would probably have copies of private keys issued by CNNIC,
and there's a bunch of attacks to get private keys via heartbleed, and a bunch
of Debian easily guessable private keys, but there's no general purpose
'penetrate SSL' attack that we know of right now.

~~~
jon-wood
Given control of a certificate authority can the Chinese government issue a
new certificate for github.com? I assume they can enforce that computers sold
in China have their authority in the default trust list, at which point I
think all bets are off when it comes to SSL.

------
ppierald
<script src="..." is very dangerous. At best, you can vet the src and check to
see if it's benign or not. Often times, that vendor and their "1-line of
javascript to get our whiz-bang service" in turn loads other javascript files.
I don't see how cryptographically signing the bootloader solves anything in
this case. Compromised analytics or vendor javascript will still lead to total
site pwnage if I'm reading this right.

~~~
lwf
This protects you from providers that go rogue or are compromised __after
__you enable their JS.

It also lets you use CloudFront as a CDN for your own JS without having to
trust them to serve the content as you described it, if you calculate your
hashes based on the scripts you sent them.

~~~
Macha
The parent poster's point is about providers that tell you to include script A
which then loads X and Y. Knowing A can't change isn't very helpful in this
situation as X and Y could change.

------
xsmasher
Careful! I've seen proxies (TracFone I think) subtly modify JSON files by
removing whitespace, probably in the name of download speed. That will break
the hashing.

If you start seeing unexplained errors on pay-as-you-go phones, you'll know
why; although if this facility gains popularity then I'm sure they'll be
pressured to stop modifying content.

~~~
adrianmacneil
This is not possible if you are loading resources over HTTPS (unless the
carrier has installed a root certificate on your device, in which case you're
not in a great place security-wise anyway).

------
ejcx
By the way. I have an SRI tester to determine if your browser supports SRI.
It's still very new and doesn't have a lot of support

[https://ejj.io/sri/](https://ejj.io/sri/)

------
knweiss
The next step: A distributed, content-addressed caching system that allows the
web browser to fetch the data from the fastest/nearest caching server _by_
_hash_.

IPFS comes to mind.

------
nailer
Edit : post below is right, nonces are only for inline scripts
[https://bugs.webkit.org/show_bug.cgi?id=89577](https://bugs.webkit.org/show_bug.cgi?id=89577)

original: IIRC CSP already has hashes for resources, which also would handle
this purpose.

As a side note, there's at least one CDN already hosting fake copy of
bootstrap - I've seen a mlicious extension loading it in my report-uri.io
logs.

~~~
detaro
afaik CSP hashes are only for inline resources, but I could be wrong on that.

------
deftnerd
You can use [https://srihash.org](https://srihash.org) to hash links and
update your HTML.

------
linksbro
This is great, but only if your CDN is not also serving your HTML files!
(static sites)

~~~
adrianmacneil
For a static site I expect you would be far less concerned about session
hijacking or XSS if someone took over that domain. Even a complete single-page
app should serve the initial html request from a trusted domain/server.

------
dchest
Should be "sha256-..." (without dash between sha and 256)

~~~
mastahyeti
Thanks. I updated the post and opened a PR to fix the README on sprockets-
rails. [https://github.com/rails/sprockets-
rails/pull/273](https://github.com/rails/sprockets-rails/pull/273)

------
sarciszewski
This is an excellent idea. So long as you trust the server you're talking to,
and it's using TLS, you can eliminate attack vectors by a compromised CDN this
way.

Bravo. :)

------
Animats
It's nice that Github, Inc. likes subresource integrity. Did they put it on
their web pages? As of right now, it doesn't seem to be on their home page.
The next big step is for Wordpress to support it.

Subresource integrity is in some ways more important than "HTTPS Everywhere",
because the MITM-as-a-service sites such as Cloudflare subvert HTTPS
Everywhere. For security reasons, you might choose to serve your home page and
a few security-critical pages from your own server, without using a CDN. But
run everything else through the CDN, using subresource integrity to keep the
CDN honest.

With subresource integrity, many items no longer need to be encrypted. This is
good for security. Encryption interferes with caching, and HTTPS in front of
caches means that the attack surface is larger, and includes the CDN.

(Yes, there's an argument that HTTPS conceals what the user was browsing. Not
really. Checking document length will provide a good hint on what static asset
was read. The pattern of document lengths requested tends to fingerprint the
page being read.)

~~~
gellerb
Login and inspect the home page afterwards.
[http://imgur.com/bwUHgcT](http://imgur.com/bwUHgcT)

~~~
Animats
I'm logged in. Not seeing it. Maybe it's not deployed for all accounts yet.

~~~
mastahyeti
It's only included for browsers that support it. That's Chrome>45 and
Firefox>43.

~~~
Animats
Serving different content based on the user agent? Bad site. No donut.

