Skip to content

Change script inclusion to be compatible with CSP hashes #12825

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

Closed
ChaosCrafter opened this issue Nov 1, 2018 · 5 comments
Closed

Change script inclusion to be compatible with CSP hashes #12825

ChaosCrafter opened this issue Nov 1, 2018 · 5 comments

Comments

@ChaosCrafter
Copy link

ChaosCrafter commented Nov 1, 2018

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [ x ] feature request

Command (mark with an x)

- [ ] new
- [ x ] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Versions

$ node --version
v9.4.0

/c/Dev/GPCAWS/GPCAWS (feature/Bug-fix_for_melbtime)
$ npm --version
5.6.0

/c/Dev/GPCAWS/GPCAWS (feature/Bug-fix_for_melbtime)
$ ng --version

 _                      _                 ____ _     ___
/ \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|

/ △ \ | '_ \ / | | | | |/ _ | '__| | | | | | |
/ ___ | | | | (
| | || | | (| | | | || | | |
// __| ||_, |_,||_,|| _|||
|___/

Angular CLI: 6.0.8
Node: 9.4.0
OS: win32 x64
Angular: 6.0.9
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package Version

@angular-devkit/architect 0.6.8
@angular-devkit/build-angular 0.6.8
@angular-devkit/build-optimizer 0.6.8
@angular-devkit/core 0.6.8
@angular-devkit/schematics 0.6.8
@angular/cdk 6.4.1
@angular/cli 6.0.8
@angular/material 6.4.1
@ngtools/webpack 6.0.8
@schematics/angular 0.6.8
@schematics/update 0.6.8
rxjs 6.2.2
typescript 2.7.2
webpack 4.8.3

Windows 10

Repro steps

build any angular site - it will add the scripts inline after the app-root
e.g.

<body>
  <app-root></app-root>
  <script type="text/javascript" src="runtime.a66f828dca56eeb90e02.js"></script>
  <script type="text/javascript" src="polyfills.aa65e3378ecb188e0792.js"></script>
  <script type="text/javascript" src="scripts.f9bdf93c4ffe3565303b.js"></script>
  <script type="text/javascript" src="main.9742cee6e57f256e947f.js"></script>
</body>

View the site through any system that adds CSP headers, with content-security-policy:"script-src 'self'"
This will show errors in the console log as the scripts cannot be loaded.

The log given by the failure

The log is in the browser when the site is accessed.
It returns...

Refused to run the JavaScript URL because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

The problem here is that nonces would need to be dynamically injected each time the page was loaded, and the hashes would need to be recalculated every time contnet changed. The nonces is a fix that might be possible in the future in amazon, but isn't yet. The hashes would be difficult as they would have to be calculated eash build and pushed to whatever was injecting the CSP data.

Desired functionality

change the compilation to move all dynamic (compiled) scripts into the header and call them using a single constant static script to allow CSP to use script hashes for the inline script, and local file auth for the other scripts. That way the scripts can be set up securely.

Ideally the only inline script would be a simple, static script that could have a constant hash used in the CSP (for example "start()"). It would pre-load the scripts from locally. The CSP would be "script-src 'self' 'sha-{base64hashofstaticcontent}'" to allow just local files and the one static script (start() in the example below.
The code would then appear as

  <script type="text/javascript" src="runtime.a66f828dca56eeb90e02.js"></script>
  <script type="text/javascript" src="polyfills.aa65e3378ecb188e0792.js"></script>
  <script type="text/javascript" src="scripts.f9bdf93c4ffe3565303b.js"></script>
  <script type="text/javascript" src="main.9742cee6e57f256e947f.js"></script>
  <body>
    <app-root></app-root>
    <script type="text/javascript">start();</script>
  </body>

This will allow proper securing of sites against script injection in-page by denying all inline scripts except ones specifically allowed by csp hash. It avoids the need to open site security by using script-src 'unsafe-inline';

Mention any other details that might be useful

Steps to reproduce.

  1. deploy a site to an S3 bucket.

  2. set up cloud-front to force https and to allow header injection through lambdas

  3. set up the lambdas to include script-src 'self';
    sample lambda code as follows ...

'use strict';
exports.handler = (event, context, callback) => {
    
    //Get contents of response
    const response = event.Records[0].cf.response;
    const headers = response.headers;

//Set new headers 
 headers['strict-transport-security'] = [{key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubdomains; preload'}]; 
 headers['content-security-policy'] = [
     {key: 'Content-Security-Policy', 
      value: "default-src 'none'; img-src 'self' data:; font-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'"}]; 
 //  'unsafe-inline'
 headers['x-content-type-options'] = [{key: 'X-Content-Type-Options', value: 'nosniff'}]; 
 headers['x-frame-options'] = [{key: 'X-Frame-Options', value: 'DENY'}]; 
 headers['x-xss-protection'] = [{key: 'X-XSS-Protection', value: '1; mode=block'}]; 
 headers['referrer-policy'] = [{key: 'Referrer-Policy', value: 'same-origin'}]; 
    
    //Return modified response
//    return response;
    callback(null, response);
};
  1. access the site through it's cloud-front address and observe the console errors caused by the security tokens.

While this may seem like an AWS issue, the core of the issue is that there is content in the page that we have no control of and that is not compliant with modern security standards.

@wvanderdeijl
Copy link

See #6872

@ChaosCrafter
Copy link
Author

#6872 appears related but not the same - the goal in both is better CSP but they touch different aspects (assuming I'm understanding correctly.)

@clydin
Copy link
Member

clydin commented Nov 2, 2018

In production mode (which defaults to using AOT), there are no runtime generated scripts (neither eval nor Function() as well). The CSP configuration fragment shown above will work successfully and is used extensively in production websites. The problem you are encountering is either due to the addition of third party code within the application that would need additional CSP rules; or a deployment/configuration issue. (baseHREF for instance on the configuration side)

@clydin
Copy link
Member

clydin commented Mar 1, 2019

Closing due to inactivity with no further information provided.

@clydin clydin closed this as completed Mar 1, 2019
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants