Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Should CDN example on Download documentation page contain Subresource Integrity info? #13968

Open
hakanson opened this issue Feb 7, 2016 · 19 comments

Comments

@hakanson
Copy link

hakanson commented Feb 7, 2016

https://docs.angularjs.org/misc/downloading which is sourced from downloading.ngdoc contains a "Including angular scripts from the Google CDN" section with this example for downloading from the Google CDN server:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>

With Subresource Integrity available in some browsers, should this example be updated to include an integrity attribute?

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"
        integrity="sha384-hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0"
        crossorigin="anonymous"></script>

This value was determined by downloading the minified 1.4.5 file and computing the hash using:

wget https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js 
cat angular.min.js | openssl dgst -sha384 -binary | openssl enc -base64 -A

This is a good suggestion from a security perspective, but requires the documentation to be updated with a new integrity attribute along with every version change. It also would require the developer to understand the purpose of this attribute value, because if they copy that example and only change 1.4.5 to 1.4.6, the script will not load and the developer will get a potentially confusing error in the Console like:

Failed to find a valid digest in the 'integrity' attribute for resource 'https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js' with computed SHA-256 integrity 'RIkiUZXLM0fYBgxgKBSCPnFxlu37oguHYe96c9t+HAg='. The resource has been blocked.

However, I would like to see the hashed for Subresource Integrity published somewhere, even if the Download documentation isn't the right place.

@petebacondarwin
Copy link
Member

This sounds like an excellent idea. Although I am wondering if the safest path is to encourage people to use a published version. Isn't it better that a developer downloads a copy of the library, checks that it is valid and then generates their own SRI? That way they know for sure what content they are receiving.

@hakanson
Copy link
Author

hakanson commented Feb 8, 2016

I agree it is best to download a copy and serve it yourself. However, many tutorials reference a CDN and if you use the Google CDN it is likely the browser gets a cache hit.

I was brainstorming that on every "release" (e.g. 1.4.9, 1.5.0, 1.5.1, etc), the integrity hash values could be generated and put into a SRI.json file. Those values could be used to both feed the documentation and used as input into a grunt/gulp/whatever build task for projects using angular.js to add the integrity attribute to script tags.

I'm not sure of the best solution, nor know of other libraries to look at as examples, but wanted to raise as an issue for the discussion on what to do.

@ScottHelme
Copy link

I'm not sure that I agree it's better to host your own copy as that can result in a worse experience for the user in a few ways. Using an asset from a CDN increases the chance that the user will already have it in their cache, reducing bandwidth requirements and potentially cost. This also improves performance which results in a better UX. SRI resolves the trust issue of allowing a 3rd party to serve your assets.

Many projects already provide checksum/integrity values for their downloads and SRI is, in effect, a method of automating that process in the browser. If we can't trust the integrity values provided by the project then we have greater concerns. Also, is a developer realistically going to review the entire Angular code base before generating their own integrity value?

The only addition I'd make here is that the provided script tags for each release should include more than the sha384 integrity value. A browser will always chose the strongest hash that it supports so it could be a good idea to include the sha256 and sha512 values for backwards and forwards compatibility too. As Kevin mentioned, there are simple methods to produce these values and include them in documentation for wider circulation.

@petebacondarwin
Copy link
Member

I wasn't suggesting that one hosts their own copy. I was just saying that if you can't rely upon the CDN being valid then why should you rely upon us providing a valid hash? I was suggesting that you use the CDN but then generate your own hash from a copy downloaded from the CDN that you have confirmed is valid.

@petebacondarwin
Copy link
Member

We will discuss this in the team meeting today and come up with a plan.

@petebacondarwin petebacondarwin self-assigned this Feb 8, 2016
@ScottHelme
Copy link

Ok, self hosting aside as that seems to have taken us off topic, we still need to depend on you guys to provide the hash.

If we download a copy from a CDN where and how do we validate that? We're going to turn to you guys and say 'is this valid?'. That's exactly what integrity hashes are for, both in the context of SRI and otherwise. You as the author define the hash that all others are checked against. Failing that I'm not sure what other method we have to validate the file.

@petebacondarwin
Copy link
Member

OK, so we discussed this in our team meeting. Here is the plan:

  • add the hash for the core angular.min.js to the download button on https://angularjs.org
  • when we build a release, generate a text file contain a hash for each of our distribution files (i.e. each module's .js and .min.js file) and place these files in the appropriate folder on https://code.angularjs.org
  • add some documentation explaining what these files are and what to do with them

Is this acceptable?
PRs are most welcome :-)

@hakanson
Copy link
Author

hakanson commented Feb 9, 2016

What were you thinking for file extension and format? I initially thought of the .md5 and .sha1 style extensions, but would you want to generate .sha256 , .sha384 , and .sha512 files? Also, a file with that style extensions would appear to be compatible with shasum but the shasum utility generates hex values and includes the filename.

shasum -a 384 angular.min.js 
857348f426fc3890b7faad74b440bb454cda0c458a8c8422135960fad148aedb5e7c81be49c5022aa3a541512a726334  angular.min.js

I am wondering if you should generate an .integrity file with all the valid prefixed and base64-encoded hashes? Here would be an example of angular.min.js.integrity

sha256-RPPsQcSPq5bHR3vDUWpr9XR/NHMe9QAJ8Uwffw3LBDM=
sha384-hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0
sha512-y2SOwfsp2w/M2K9LzWRyFd/V62w3z9frSvAB96p7AJlyNIF7O40A6ezctVEgyI2gap6ikSoFpSrtC8Gztmjp4A==

The contents from a file like this could be used directly by IDEs or build tasks to insert / verify the value of the integrity attribute into the script tag.

@petebacondarwin
Copy link
Member

I like the idea of the integrity file, I would consider going further and just provide the full script tag in those files... My motivation is that really what we want is to make it super-simple for developers to use the integrity values, right?

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"
        integrity="sha256-RPPsQcSPq5bHR3vDUWpr9XR/NHMe9QAJ8Uwffw3LBDM="
        crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"
        integrity="sha384-hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0"
        crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"
        integrity="sha512-y2SOwfsp2w/M2K9LzWRyFd/V62w3z9frSvAB96p7AJlyNIF7O40A6ezctVEgyI2gap6ikSoFpSrtC8Gztmjp4A=="
        crossorigin="anonymous"></script>

@ScottHelme
Copy link

Yeah, I like the idea of the full tag being generated, it's less work to implement then. It's also worth noting that you can/should specify multiple integrity attributes in the same tag and the browser will automatically select the strongest it supports. This allows for wider support of SRI in various browsers and reduces the problems if support for a hash were to be dropped due to future events.

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"
    integrity="sha256-RPPsQcSPq5bHR3vDUWpr9XR/NHMe9QAJ8Uwffw3LBDM="
    integrity="sha384-hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0"
    integrity="sha512-y2SOwfsp2w/M2K9LzWRyFd/V62w3z9frSvAB96p7AJlyNIF7O40A6ezctVEgyI2gap6ikSoFpSrtC8Gztmjp4A=="
    crossorigin="anonymous">
</script>

This is covered in the SRI spec: https://www.w3.org/TR/SRI/#agility

@hakanson
Copy link
Author

hakanson commented Feb 9, 2016

I like the idea of making it as simple as possible, because I fear most developers won't take the time to figure out how to use the raw integrity hash data.

Is there a concern this "unfairly" promotes the Google CDN. If a user happens to use a different CDN host like cdnjs, they need to change the src. I don't think there is an issue, but wanted to raise the point.

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js"
    integrity="sha256-RPPsQcSPq5bHR3vDUWpr9XR/NHMe9QAJ8Uwffw3LBDM="
    integrity="sha384-hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0"
    integrity="sha512-y2SOwfsp2w/M2K9LzWRyFd/V62w3z9frSvAB96p7AJlyNIF7O40A6ezctVEgyI2gap6ikSoFpSrtC8Gztmjp4A=="
    crossorigin="anonymous">
</script>

@petebacondarwin
Copy link
Member

@hakanson well it is a Google project :-)

@gkalpak gkalpak modified the milestones: 1.5.1, 1.5.2 Mar 16, 2016
@matsko matsko modified the milestones: 1.5.2, 1.5.3 Mar 18, 2016
@petebacondarwin petebacondarwin modified the milestones: 1.5.3, 1.5.4 Mar 25, 2016
@petebacondarwin petebacondarwin modified the milestones: 1.5.5, 1.5.6 Apr 18, 2016
@hakanson
Copy link
Author

Were you thinking of using the grunt-sri payload.json format?

{
    "payload": {
        "@angular.min.js": {
            "path": "angular.min.js",
            "type": null,
            "integrity": "sha256-RPPsQcSPq5bHR3vDUWpr9XR/NHMe9QAJ8Uwffw3LBDM= sha384-hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0 sha512-y2SOwfsp2w/M2K9LzWRyFd/V62w3z9frSvAB96p7AJlyNIF7O40A6ezctVEgyI2gap6ikSoFpSrtC8Gztmjp4A==",
            "hashes": {
                "sha256": "RPPsQcSPq5bHR3vDUWpr9XR/NHMe9QAJ8Uwffw3LBDM=",
                "sha384": "hXNI9Cb8OJC3+q10tEC7RUzaDEWKjIQiE1lg+tFIrttefIG+ScUCKqOlQVEqcmM0",
                "sha512": "y2SOwfsp2w/M2K9LzWRyFd/V62w3z9frSvAB96p7AJlyNIF7O40A6ezctVEgyI2gap6ikSoFpSrtC8Gztmjp4A==",
            }
        }
    }
}

it seems more robust that the gulp-sri JSON

{
    "path/to/file/relative/to/project/root/filename.ext": "srihash",
    //other entries 
}

@petebacondarwin
Copy link
Member

grunt-sri looks like a good option

@Narretz Narretz modified the milestones: 1.5.6, 1.5.7 May 27, 2016
@gkalpak gkalpak modified the milestones: 1.5.7, 1.5.8 Jun 15, 2016
@hakanson
Copy link
Author

@petebacondarwin
Copy link
Member

PR anyone??

@petebacondarwin petebacondarwin modified the milestones: 1.5.8, 1.5.9 Jul 22, 2016
@petebacondarwin
Copy link
Member

I started a bit of PR for this....

#15220

@petebacondarwin petebacondarwin modified the milestones: 1.6.x (post 1.6.0), 1.5.9 Oct 6, 2016
@Narretz Narretz modified the milestones: 1.6.x, 1.7.x Apr 12, 2018
@petebacondarwin
Copy link
Member

I don't think there is a great deal of interest in doing this.

@petebacondarwin petebacondarwin modified the milestones: 1.7.x, 1.7.x - won't fix May 21, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants