AngularJS Security Fundamentals
Liran Tal
Posted on March 29, 2020
Below are a short set of 10 AngularJS security fundamentals best practices that I'll cover in this blog post. See original link for more in-depth details and code snippets.
Or you could just download this lovely PDF and pin it in your wall to never lose sight of these AngularJS Security Fundamentals:
Why am I even talking about AngularJS?
Angular v1.x makes up for, approximately, 30% of all Angular version downloads and just over 2 million downloads in July 2019.
1. The “Angular way” safeguards you from XSS
AngularJS by default applies automatic output encoding and input sanitization that is context-aware for any data values that are pushed on to the DOM. As long as you are doing things the “Angular” way you benefit from this safeguard.
Using Angular’s ng-bind
Angular’s ng-bind directive allows you to bind value to an HTML’s element value from the one that was set in Angular’s code, such as the controller.
<div class="jumbotron" ng-controller="AboutController as about">
<h1>About</h1>
<p>
Signed by:
</p>
<div ng-bind="about.signature"></div>
</div>
Using Angular curly braces
Another way to bind data value into their HTML elements values is by using Angular’s convention of double curly braces. Both ngBind‘s directive and curly braces’ notation is the same, with some subtle differences regarding the UX.
Here’s an example of how Angular encodes malicious data when using curly braces, starting off with adding a description value to the view:
<div class="jumbotron" ng-controller="AboutController as about">
<h1>About</h1>
<p>
{{ about.description }}
</p>
<p>
Signed by:
</p>
<div ng-bind="about.signature"></div>
</div>
2. Avoid using Angular DOM-related input injection
Key takeaway: Avoid using Angular DOM-related input injection which may introduce vulnerabilities.
- In Angular 1.2 and prior avoid using the ng-bind-html-unsafe directive
- In Angular 1.2 and later avoid blindly trusting user input with Strict Contextual Escaping collection of methods such as $sce.trustAsHtml(value)
Earlier AngularJS versions such as 1.2 and prior had an ng-bind-html-unsafe
directive which allowed to insert HTML data into the DOM and create new elements. Some practices for using this was to create DOM elements straight from data input and then filter certain strings in them, like remove links and others.
Using this approach to black list data is error-prone and not always safe due to new attack vectors and methodologies that are discovered over time and require maintaining such black list.
The AngularJS 1.2 release has deprecated the ng-bind-html-unsafe
directive and introduced Strict Contextual Encoding (SCE) instead. SCE enables escaping and sanitization data based on a context but not on a specific HTML element’s data.
That said, escape hatches exist that allow you forgo the encoding and assume that the data provided is safe to use. Such actions are made possible with Angular’s methods $sce.trustAsHtml()
and $sce.trustAs(type, value)
.
3. Avoid dynamically loading Angular templates from untrusted sources
Angular code makes use of Angular templates all the time. These HTML templates look like this:
<div>
Hello, {{ name }}
</div>
This introduces the risk of insecurely loading templates over untrusted domains that are beyond the control and trust of the web application. Moreover, developers should take further note of accessing the templates over secure protocols such as up-to-date versions of TLS to mitigate Man-In-The-Middle attacks.
An example of how an Angular template is loaded dynamically over the network:
angular.module(‘myModule’)
.component(‘myComponent’, {
templateUrl: ‘/path/to/template.html’,
controller: function() {}
});
4. AngularJS open redirect vulnerabilities
The browser-native APIs provide page navigation capabilities, such as $window.location
. Angular abstracts the navigation handling with the $location
service provider and provides methods such as $location.url()
, $location.path()
and $location.hash()
, as well as others, to access the current navigation URL and synchronises it, as required.
You possibly have Angular code that performs navigation based on URL query parameters or other URL related data.
However, since the URL address is in the control of the user browsing the web application, that means a user can set the hash to valid JavaScript code — for example https://www.example.com/path/to/this#javascript:alert(1)
— and execute that URL.
Likewise, by setting window.location.href
to user input — for example, the JavaScript injection example on the hash — would result in the same thing.
Key takeaway: Avoid open direct pitfalls by implementing user-provided input directly to perform page navigation.
Avoid patterns such as window.location.href = $location.hash
which potentially lead to JavaScript Code Injection attacks.
Use dictionary maps to perform page navigation based on user-provided input.
5. Server-side Angular code injection
Best practices to mitigate server-side Angular code injection:
- Avoid mixing server-side and client-side templates and instead treat templates only within one application context: either the server-side or the client-side.
reduce the scope of
ng-app
directive from an HTML’s document body to specific DOM element context within the page itself. - Bind the data from the template to
ng-bind
orng-bind-html
to ensure user input is being properly handled with Angular’s support for output encoding and sanitization controls with these Angular directives. - Use
ng-non-bindable
to make sure the data is not being treated by Angular as an expression that needs to be evaluated and so mitigating the Angular code injection.
6. Avoid using the Angular .element jQuery-compatible API to manipulate the DOM
More about angular.element from Angular’s official documentation on https://docs.angularjs.org/api/ng/function/angular.element.
Key takeaway: Avoid using Angular’s angular.element() jQuery-compatible API to manipulate the DOM as this leads to potential Cross-site Scripting vulnerabilities due to directly creating HTML elements on the DOM.
7. Use Angular security linters
Linters are common in the world of JavaScript development and often developers make use of a popular project like ESLint along with plugins that extend it. The eslint-plugin-angular
project helps with general Angular coding conventions and guidelines. It also has some rules for security, one of which is no-jquery-angularelement
that disallow wrapping of angular.element objects with jQuery or $.
Key takeaway: Use static code analysis tools to automate finding insecure code and alerting developers when this happens, early in the process of development. Security linters that are part of AngularJS security fundamentals:
- eslint-plugin-scanjs-rules
- eslint-plugin-angular disallow angular’s angular.element() usage
8. Scan and fix vulnerabilities in Angular third-party components
It’s highly likely that you are using open source packages on top of the Angular core and its extended components in order to build your web application. In fact, the AngularJS project itself has vulnerabilities. According to a study on JavaScript Frameworks Security by Snyk, AngularJS has over 20 security vulnerabilities across the Angular 1.x version branch.
Moreover, there the dependencies you use to build your Angular-based web application that possibly have security vulnerabilities too. As the following table shows, some of those vulnerabilities don’t even have an available fix, to date.
Scan for vulnerabilities
Looking for an AngularJS security scanner? To stay up to date with security vulnerabilities on your frontend project, use Snyk and connect your GitHub or Bitbucket projects — that way Snyk automatically finds and creates fix pull requests for you.
Another quick way to get started is to use the Snyk CLI:
npm install -g snyk
snyk test
When you run a Snyk test, Snyk reports the vulnerabilities found and displays the vulnerable paths so you can track the dependency tree and understand which module introduced a vulnerability.
Snyk provides you with actionable remediation advice in order to upgrade to a fixed version through an automated pull request that Snyk opens in your repository. You can also apply a patch that Snyk provides to mitigate the vulnerability if no fix is available.
If you’re looking for anything close to an AngularJS security scanner you should start with Snyk as a way to track your open source dependencies, get notified, and fix them as vulnerabilities are discovered.
Key takeaway: AngularJS has over 20 vulnerabilities to date and there are Angular components with millions of downloads that are still vulnerable.
- Connect Snyk to GitHub or other SCMs for optimal CI/CD integration with your projects.
- Snyk finds vulnerabilities in 3rd party components you use and opens fix pull requests so you can merge the version update and mitigate the risk.
9. Built-in CSRF support for Angular applications
Angular has a built-in support for CSRF tokens in which it reads cookies of specific naming conventions, such as XSRF-TOKEN, that is sent from the server and appends the value to further HTTP requests being made from the Angular application.
The entire CSRF token handling is done within the $http service for AngularJS. For newer Angular versions it is also provided via the HttpClient in the officially supported @angular/common/http
module. It also provides further configuration of the cookie name for the CSRF token and general behavior via the $http.xsrfCookieName
API and others.
Key takeaway: Angular has built in support for CSRF token handling on the client-side via its $http
service. Use this service instead of rolling your own.
10. Angular’s built-in CSP compatibility
AngularJS has CSP-related built-in controls but when enabled, it has to exclude some functionality — for example, not allowing inline scripts and expressions, due to eval() not being permitted. Yet, this is internally required by AngularJS for some of its features.
Recommended reading on CSP is on Mozilla’s website and Angular’s API documentation for the ngCsp
directive.
Key takeaway: Implementing a Content Security Policy (CSP) is an important step in providing an additional layer of security, especially one that helps mitigate Cross-site Scripting attacks.
--
I am a Developer Advocate at Snyk. This post originally appeared on the Snyk blog, with even more security tips where you can find the full article on AngularJS security fundamentals as well as an easily shareable pdf.
Posted on March 29, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.