-
Notifications
You must be signed in to change notification settings - Fork 27.3k
ngCsp not enough to avoid CSP errors if using inline javascript #14347
Description
Following angular documentation for ngCsp looks like just by using the directive is not enough to avoid errors if you use inline scripts. Even after following the guidelines we were still getting randomly the below errors causing angular to stop working and consequently blank content. The reason why it was random was that we had inline javascript coming up from Google mod-pagespeed randomly in the page.
I think Angular should probably just detect if ng-csp is being used to avoid executing inline scripts in such case. It could also come up with a non eval way if there is still a need to run inline scripts just as it does with the "Angular's built-in subset of jQuery, called 'jQuery lite' or jqLite". At a minimum the documentation should state that currently the ng-csp directive will not work if at least if there is inline javascript inside the ng-if directive. This is a problem even if the server sends unsafe-inline like in the below Apache example:
Header set Content-Security-Policy: "default-src 'self' 'unsafe-inline'"
To replicate this issue:
Step 1: Use the code below to confirm a Chrome error when your server uses "Content-Security-Policy:default-src 'self' 'unsafe-inline'"
<!DOCTYPE html>
<html lang="en" ng-app ng-csp>
<head>
<script type="text/javascript" charset="utf-8" src="jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="angular.js"></script>
</head>
<body>
<div ng-if="true">
<script>console.log('foo');</script>
</div>
</body>
</html>
Step 2: Swap jquery and angular script inclusions to confirm the error goes away
Here is a typical stacktrace:
angular.js:13424 EvalError: 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' 'unsafe-inline'". at Function.jQuery.extend.globalEval (jquery.js:343) at domManip (jquery.js:5290) at jQuery.fn.extend.after (jquery.js:5456) at domInsert (angular.js:5189) at Object.$provide.$get.$$animateQueue.enter (angular.js:5352) at angular.js:25332 at $$sanitizeUriProvider.$get.node (angular.js:8212) at angular.js:8551 at boundTranscludeFn (angular.js:8350) at controllersBoundTransclude (angular.js:9072)