Skip to content

Change script inclusion to be compatible with CSP hashes #12825

@ChaosCrafter

Description

@ChaosCrafter

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions