Skip to content
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

New: Rule SRI #875

Closed
wants to merge 3 commits into from
Closed

New: Rule SRI #875

wants to merge 3 commits into from

Conversation

molant
Copy link
Member

@molant molant commented Mar 11, 2018

Pull request checklist

Make sure you:

For non-trivial changes, please make sure you also:

  • Added/Updated related documentation.
  • Added/Updated related tests.

Short description of the change(s)

Close #26

@molant
Copy link
Member Author

molant commented Mar 11, 2018

The spec talks about integrity for script and link but all the examples are for styles so I'm not sure if it applies also for manifests, favicon, etc. Also CSP values are only for scripts and styles.
For now I'm limiting to styles and scripts and ask around.

@@ -0,0 +1,145 @@
# Require scripts and styles to use Subresource integrity (`sri`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subresource => subresource

## Why is this important?

Nowadays it's very common to use third party resources from CDNs or different
services (analytics, ads, etc.) and thus increasing the risk surface of your
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

, and thus,


Subresource integrity [is a standard][sri spec] that mitigates this by ensuring
that an exact representation of a resource, and only that representation, loads
and executes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should add a warning that this is only guaranteed over HTTPS?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put a comment in the latest comment in the next paragraph

* When using a cross-origin resource (e.g.: using a script hosted in a third
party CDN), the `<script>` tag needs to have a valid
[`crossorigin` attribute][crossorigin].
* The resource needs to be served on a [secure context][secure context]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resource is served...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

(i.e.: HTTPS)
* The hash from the `integrity` attribute needs to be the same as the one
calculated using the response's body.
* If multiple hashes are provided, at least one needs to be valid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valid.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Same-origin resource with hash function less secure than `sha384`:

```html
<script src="/script.js" integrity="sha256-validHashHere">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to be consistent we should use a random hash?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about that, but I though it was clearer this way so users reading about SRI for the first time know they need to calculate the hash and replace it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok.

```json
"sri": ["warning", {
"baseline": "sha512"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

},
"repository": "sonarwhal/sonarwhal",
"scripts": {
"build": "npm run clean && npm-run-all build:*",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add "build-release": "npm run clean && npm run build:assets && tsc --inlineSourceMap false --removeComments true",

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"extends": "../../../../.nycrc"
},
"peerDependencies": {
"sonarwhal": "^1.0.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.0.1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually 1.0.3, things move fast!

"watch:test": "ava --watch",
"watch:ts": "npm run build:ts -- --watch"
},
"version": "0.1.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add "private": true

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -0,0 +1,69 @@
{
"author": "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"watch:test": "ava --watch",
"watch:ts": "npm run build:ts -- --watch"
},
"version": "0.1.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.0.0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

"eslint-plugin-markdown": "^1.0.0-beta.7",
"eslint-plugin-typescript": "^0.10.0",
"markdownlint-cli": "^0.7.0",
"npm-link-check": "^2.0.0",
Copy link
Contributor

@alrra alrra Mar 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this ca be removed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* @fileoverview Require scripts and styles to use Subresource Integrity
*/

import * as sri from './sri';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just make a convention that if there is a single rule in a package we use rule.ts for the name of the file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


import { Category } from 'sonarwhal/dist/src/lib/enums/category';
import { RuleContext } from 'sonarwhal/dist/src/lib/rule-context';
// The list of types depends on the events you want to capture.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

debug('Is eligible for integrity validation?');

const { element, resource } = evt;
const resourceOrigin: string = new URL(resource).origin;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use same-origin as things may be more complex then this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think this code is better than the code in that package. It's using the old url.parse and doing some magic, and we get for free the origin if we use new URL. Maybe we could add a method in misc so we can remove that dependency from the project.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could add a method in misc so we can remove that dependency from the project.

👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created #879 for this

const { element, resource } = evt;
const resourceOrigin: string = new URL(resource).origin;

// CORS validation only applies to scripts, styles are OK
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are styles ok? Maybe provide a link?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the link that's just above in the method description

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

debug('Is integrity attribute valid?');
const { element, resource } = evt;
const integrity = element.getAttribute('integrity');
const integrityRegExp = /^sha(256|384|512)-/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if I have multiple integrity attributes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added another test. Only the first instance is accessible via getAttribute. Additionally, it looks like Chrome tries to download the file twice if the first hash is invalid, but only the first attribute is accessible. I've left the code of the test commented with an explanation.

}

// cross-origin scripts need to be loaded with a valid "crossorigin" attribute (ie.: anonymous or use-credentials)
const crossorigin = element.getAttribute('crossorigin');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use normalizeString?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@molant
Copy link
Member Author

molant commented Mar 13, 2018

@alrra all your feedback should be included.

@sonarwhal/core this is ready for another round.

@alrra
Copy link
Contributor

alrra commented Mar 13, 2018

Also, maybe add this to configuration-web-recommended?

@molant
Copy link
Member Author

molant commented Mar 13, 2018 via email

@@ -0,0 +1,201 @@
Apache License
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should make the release script add this file automatically for new packages?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's taken care by the generators. I wouldn't change anything TBH.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK.

@@ -0,0 +1,145 @@
# Require scripts and styles to use subresource integrity (`sri`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sri => @sonarwhal/rule-sri

@@ -0,0 +1,145 @@
# Require scripts and styles to use subresource integrity (`sri`)

`sri` warns about requesting scripts or styles without using Subresource
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

styles => stylesheets

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subresource => subresource

## Why is this important?

Nowadays it's very common to use third party resources from CDNs or different
services (analytics, ads, etc.), and thus, increasing the risk surface of your
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

increase

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure it's increasing


Nowadays it's very common to use third party resources from CDNs or different
services (analytics, ads, etc.), and thus, increasing the risk surface of your
web application.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

web site/app. ?

* [The `integrity` attribute has to be valid][sri format]. I.e.: it should
contain something in the form of `sha(256|384|512)-HASH`, where `HASH` is
the hashed value of the downlaoded body's response using the previous
algorithm (`sha256`, `sha384`, or `sha512`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously specified algorithm?

contain something in the form of `sha(256|384|512)-HASH`, where `HASH` is
the hashed value of the downlaoded body's response using the previous
algorithm (`sha256`, `sha384`, or `sha512`).
* The minium cryptographic hash function used has to be [`sha384`][collisions].
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for consistency with the others:

used has to be => used is

the hashed value of the downlaoded body's response using the previous
algorithm (`sha256`, `sha384`, or `sha512`).
* The minium cryptographic hash function used has to be [`sha384`][collisions].
If multiple are provided, the highest one will be used to determine if the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiple ones

* * base64
* * `sha384-hash`
*/
private calculateHash(content: string, sha): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sha: string

* No need to report anything, but we can stop processing things right away.
*/
const isScript: boolean = element.nodeName === 'SCRIPT' && !!element.getAttribute('src');
const isStyle: boolean = element.nodeName === 'LINK' && element.getAttribute('rel') === 'stylesheet';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalizeString(element.getAttribute('rel')) === 'stylesheet';

@molant
Copy link
Member Author

molant commented Mar 13, 2018

Feedback is pushed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add rule to check subresource integrity
2 participants