Skip to content

Commit

Permalink
fix(csp): fix autodetection of CSP + better docs
Browse files Browse the repository at this point in the history
CSP spec got changed and it is no longer possible to autodetect if a policy is
active without triggering a CSP error:

w3c/webappsec@1888295

Now we use `new Function('')` to detect if CSP is on. To prevent error from this
detection to show up in console developers have to use the ngCsp directive.

(This problem became more severe after our recent removal of `simpleGetterFn`
 which made us depend on function constructor for all expressions.)

Closes angular#8162
Closes angular#8191
  • Loading branch information
IgorMinar committed Jul 14, 2014
1 parent a2c7cf9 commit ebe467b
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 15 deletions.
21 changes: 16 additions & 5 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -921,12 +921,23 @@ function equals(o1, o2) {
return false;
}

var csp = function() {
if (isDefined(csp.isActive_)) return csp.isActive_;

var active = !!(document.querySelector('[ng-csp]') ||
document.querySelector('[data-ng-csp]'));

if (!active) {
try {
new Function('');
} catch (e) {
active = true;
}
}

return csp.isActive_ = active;
};

function csp() {
return (document.securityPolicy && document.securityPolicy.isActive) ||
(document.querySelector &&
!!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
}


function concat(array1, array2, index) {
Expand Down
25 changes: 19 additions & 6 deletions src/ng/directive/ngCsp.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
* This is necessary when developing things like Google Chrome Extensions.
*
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
* any of these restrictions.
* For Angular to be CSP compatible there are only two things that we need to do differently:
*
* - don't use `Function` constructor to generate optimized value getters
* - don't inject custom stylesheet into the document
*
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
Expand All @@ -23,7 +25,18 @@
* includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
* To make those directives work in CSP mode, include the `angular-csp.css` manually.
*
* In order to use this feature put the `ngCsp` directive on the root element of the application.
* Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
* autodetection however triggers a CSP error to be logged in the console:
*
* ```
* Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
* script in the following Content Security Policy directive: "default-src 'self'". Note that
* 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
* ```
*
* This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
* directive on the root element of the application or on the `angular.js` script tag, whichever
* appears first in the html document.
*
* *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
*
Expand All @@ -38,6 +51,6 @@
```
*/

// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
// anywhere in the current doc
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
// bootstrap the system (before $parse is instantiated), for this reason we just have
// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
9 changes: 5 additions & 4 deletions test/AngularSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,14 +413,15 @@ describe('angular', function() {


describe('csp', function() {
var originalSecurityPolicy;
var originalFunction;

beforeEach(function() {
originalSecurityPolicy = document.securityPolicy;
originalFunction = window.Function;
});

afterEach(function() {
document.securityPolicy = originalSecurityPolicy;
window.Function = originalFunction;
delete csp.isActive_;
});


Expand All @@ -430,7 +431,7 @@ describe('angular', function() {


it('should return true if CSP is autodetected via CSP v1.1 securityPolicy.isActive property', function() {
document.securityPolicy = {isActive: true};
window.Function = function() { throw new Error('CSP test') };
expect(csp()).toBe(true);
});

Expand Down

0 comments on commit ebe467b

Please sign in to comment.