AngularJS – How to Handle XSS Vulnerability Scenarios

This article represents different scenarios related with XSS (cross-site scripting) and how to handle them appropriately using AngularJS features such as SCE ($sceProvider) and sanitize service ($SanitizeProvider). Please feel free to comment/suggest if I missed to mention one or more important points. Also, sorry for the typos.
Do visit the page, how to prevent XSS attacks in Angular 2.*, Angular 4.* or Angular 5.*, if you are looking forward for handling XSS vulnerabilities in latest version of Angular apps. You may also want to check the page, Top 10 Angular Security Best Practices vis-a-vis vulnerability issues.

Following are the key XSS-related scenarios described later in this article:

  • Escape HTML completely
  • Insert HTML in Secure Way while ignoring elements such as “script”. This is as well dangerous and could deface your website, if not taken care, especially with “img” tag.
  • Trust and insert entire HTML; This is dangerous and could easily end-up defacing your website

Escape HTML using ng-bind directive

In case you want to escape HTML in entireity, you may want to use ng-bind directive. All it does is escape the HTML elements and print it as it is. Following code demonstrates the ng-bind directive usage.


<div>

<form>
	
<h1>AngularJS XSS Demo Test</h1>

	<hr/>
	
<div class="col-md-12">
	<input type="text" ng-model="name" class="form-control col-md-12" ng-change="processHtmlCode()" placeholder="Enter Some HTML Text..."/>
	</div>

</form>

</div>

<hr/>

<div style="padding:20px">
	<span><strong>ng-bind directive: Note that HTML text is entered as it is.</strong></span>
	<span ng-bind="helloMessage">{{helloMessage}}</span>
</div>

Following diagram demonstrates the above. Pay attention to the HTML code entered in the text field. It is printed as it is, on to the HTML page.

ng_bind_taj_mahal

Insert HTML in Secure Way, while Ignoring Elements such as “script”, using ng-bind-html Directive

This is key to solving XSS attacks. That said, one should still take care of elements such as “img” ( included as part of white-list; void elements) as it could display any image (including illegal ones) on your webpage, thus, defacing your webpage. Using ng-bind-html directive, javascript script tag such as “script” could be ignored straight-away. ng-bind-html directive evaluates the expression and inserts the resulting HTML into the element in a secure way. For cases where user inputs could consist of HTML (such as comments), the inclusion of ng-bind-html directive would ensure that the text is sanitize against a white-list of safe HTML tokens. The whitelist of safe tokens is coded as part of $sanitize module and mentioned below. Following is included in the safe list (taken directly from the source code):

  • Void elements: area,br,col,hr,img,wbr. The details of same could be found at http://dev.w3.org/html5/spec/Overview.html#void-elements
  • Block element: address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul
  • Inline elements: a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var
  • End Tag Elements: colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr,rp,rt. The details of same could be found at http://dev.w3.org/html5/spec/Overview.html#optional-tags

Following are two elements which are escaped as it is in untrusted category. In case, you want to show it, you would have to use $sce service and call trustAsHtml method for Angular to execute below-mentioned elements.

  • script
  • style

Following represents code sample demonstrating the ng-bind-html directive usage.


<div>

<form>
	
<h1>AngularJS XSS Demo Test</h1>

	<hr/>
	
<div class="col-md-12">
	<input type="text" ng-model="name" class="form-control col-md-12" ng-change="processHtmlCode()" placeholder="Enter Some HTML Text..."/>
	</div>

</form>

</div>

<hr/>

<div style="padding:20px">
	<span>ng-bind-html directive: Note that image is displayed appropriately as a result of text entered in the text field.</span>
	<span ng-bind-html="helloMessage"></span>
</div>

Following image demonstrates how it looks like when entering HTML code in textfield that is inserted into DOM in a secure way. Pay attention to “img” element which is a part of Void elements in above list. As the code is entered in the textfield, the image appeared as “img” is in trusted list (white-list)

ng_bind_html_taj_mahal

Trust and Insert entire HTML

Warning: This is dangerous and could easily end-up defacing your website. Only when you know and are doubly sure, you should use trustAsHtml. In case, you are confident that the text content could be trusted, you could use $sce service and call trustAsHtml method which then inserts entire HTML into the DOM. Pay attention to the HTML and javascript code snippet where $sce service is used to invoke trustAsHtml method to trust the HTML code. In that case, one code such as “<style>.hello{color:red}</style>” is inserted, it ended up painting already existing HTML element. This may not be healthy. One could change the background images with illegal images that way.

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20type%3D%22text%2Fjavascript%22%3E%0A%09angular.module('HelloApp'%2C%20%5B%22ngSanitize%22%5D)%0A%09.controller('HelloCtrl'%2C%20%5B'%24scope'%2C%20'%24sce'%2C%20function(%24scope%2C%20%24sce)%7B%0A%09%09%24scope.name%3D%22%22%3B%0A%09%09%24scope.processHtmlCode%09%3D%09function()%20%7B%0A%09%09%09%24scope.helloMessage%20%3D%20%22%3C%2Fp%3E%0A%3Ch1%3E%22%20%2B%20%24scope.name%20%2B%20%22%3C%2Fh1%3E%0A%3Cp%3E%22%3B%09%0A%09%09%09%24scope.trustedMessage%20%3D%20%20%24sce.trustAsHtml(%20%24scope.name%20)%3B%0A%09%09%7D%0A%09%7D%5D)%0A%0A%09%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
<!-- Pay attention to class hello which is coded in UI and as a result, element is painted in red-->

<div style="padding:20px">
		<span class="hello"><strong>ng-bind directive: Note that HTML text is entered as it is.</strong></span>
		<span class="hello" ng-bind="helloMessage">{{helloMessage}}</span>
</div>

<hr/>

<div style="padding:20px">
		<span>Note that script tag is executed as well.</span>
		<span ng-bind-html="trustedMessage"></span>
</div>

Following image demonstrates how it looks like when entering HTML style code in textfield that is inserted into DOM. As a result, the other HTML element is painted in red as shown below. In scenarios where a hacker could insert an style element with background, this could show-up unwanted background and bring bad experience for the end users.

ng_bind_html_trust_html

Entire Code – Cut/Copy and Paste and Play

<html>
<head>
	<title>Hello AngularJS</title>
	<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
	<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20type%3D%22text%2Fjavascript%22%20src%3D%22http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.3%2Fangular.min.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
	<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20type%3D%22text%2Fjavascript%22%20src%3D%22http%3A%2F%2Fajax.googleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.3.3%2Fangular-sanitize.min.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
</head>
<body class="container" ng-app="HelloApp" ng-controller="HelloCtrl">
	
<div>
		
<form>
			
<h1>AngularJS XSS Demo Test</h1>

			<hr/>
			
<div class="col-md-12">
				<input type="text" ng-model="name" class="form-control col-md-12" ng-change="processHtmlCode()" placeholder="Enter Some HTML Text..."/>
			</div>

		</form>

		<hr/>
	</div>

	<hr/>
	
<div style="padding:20px">
		<span class="hello"><strong>ng-bind directive: Note that HTML text is entered as it is.</strong></span>
		<span class="hello" ng-bind="helloMessage">{{helloMessage}}</span>
	</div>

	<hr/>
	
<div style="padding:20px">
		<span>Note that script tag is executed as well.</span>
		<span ng-bind-html="trustedMessage"></span>
	</div>

	<hr/>
	
<div style="padding:20px">
		<span>ng-bind-html directive: Note that image is displayed appropriately as a result of text entered in the text field.</span>
		<span ng-bind-html="helloMessage"></span>
	</div>

	<hr/>
	<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20type%3D%22text%2Fjavascript%22%3E%0A%09angular.module('HelloApp'%2C%20%5B%22ngSanitize%22%5D)%0A%09.controller('HelloCtrl'%2C%20%5B'%24scope'%2C%20'%24sce'%2C%20function(%24scope%2C%20%24sce)%7B%0A%09%09%24scope.name%3D%22%22%3B%0A%09%09%24scope.processHtmlCode%09%3D%09function()%20%7B%0A%09%09%09%24scope.helloMessage%20%3D%20%22%3C%2Fp%3E%0A%3Ch1%3E%22%20%2B%20%24scope.name%20%2B%20%22%3C%2Fh1%3E%0A%3Cp%3E%22%3B%09%0A%09%09%09%24scope.trustedMessage%20%3D%20%20%24sce.trustAsHtml(%20%24scope.name%20)%3B%0A%09%09%7D%0A%09%7D%5D)%0A%0A%09%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
</body>
</html>

 

Ajitesh Kumar
Follow me

Ajitesh Kumar

I have been recently working in the area of Data analytics including Data Science and Machine Learning / Deep Learning. I am also passionate about different technologies including programming languages such as Java/JEE, Javascript, Python, R, Julia, etc, and technologies such as Blockchain, mobile computing, cloud-native technologies, application security, cloud computing platforms, big data, etc. For latest updates and blogs, follow us on Twitter. I would love to connect with you on Linkedin. Check out my latest book titled as First Principles Thinking: Building winning products using first principles thinking. Check out my other blog, Revive-n-Thrive.com
Posted in Application Security, Javascript, Web. Tagged with , , , .

Leave a Reply

Your email address will not be published. Required fields are marked *