![]()
Cross-Site Scripting (XSS) is a security vulnerability that allows attackers to inject malicious scripts into web applications, potentially stealing data, hijacking user sessions, or defacing websites. While AngularJS has built-in protections against XSS, developers must follow best practices to ensure complete security.
1. Understanding XSS in AngularJS
XSS occurs when an attacker injects malicious JavaScript into a web page, which then executes in a user’s browser. There are three main types:
- Stored XSS: Malicious script is permanently stored (e.g., in a database) and executed when a user accesses the affected page.
- Reflected XSS: The script is embedded in a URL and executed when a user clicks the malicious link.
- DOM-based XSS: The attack modifies the page’s DOM at runtime without needing a server request.
Example of an XSS Attack
<input type="text" ng-model="userInput">
<p> {{ userInput }} </p>
If a user enters <script>alert('XSS!');</script>, the script executes, demonstrating a DOM-based XSS attack.
2. Built-in XSS Protection in AngularJS
AngularJS automatically escapes dangerous characters in bindings ({{ }}) and sanitizes input in ng-bind, making it harder for XSS to occur.
Safe Usage: AngularJS Escapes Input Automatically
<p>{{ userInput }}</p>
If userInput = "<script>alert('XSS');</script>", AngularJS renders it as:
<p><script>alert('XSS');</script></p>
Unsafe Usage: Using ng-bind-html without sanitization
<p ng-bind-html="userInput"></p> <!-- Allows execution of raw HTML -->
If userInput contains <script>alert('XSS!');</script>, the script executes, making it vulnerable.
3. Preventing XSS in AngularJS
A. Always Use AngularJS Built-in Binding ({{}})
AngularJS automatically escapes special characters in {{ userInput }} to prevent execution.
Safe:
<p>{{ userInput }}</p>
Unsafe (Direct InnerHTML Assignment):
<p ng-bind-html="userInput"></p> <!-- XSS Risk -->
B. Use $sce for Trusting Content Carefully
AngularJS provides $sce (Strict Contextual Escaping) to mark content as trusted.
Use $sce.trustAsHtml() Only for Trusted Sources
app.controller('MainCtrl', function($scope, $sce) {
$scope.safeHtml = $sce.trustAsHtml("<b>Safe Content</b>");
});
Use $sce in the View
<p ng-bind-html="safeHtml"></p>
Never Trust User Input Without Validation
$scope.userInput = $sce.trustAsHtml($userInput); // Unsafe
C. Sanitize User Input Using $sanitize
For applications that must allow some HTML, use the ngSanitize module.
Install ngSanitize and Include It
var app = angular.module('myApp', ['ngSanitize']);
Sanitize User Input
app.controller('MainCtrl', function($scope, $sanitize) {
$scope.safeInput = $sanitize(userInput);
});
Use It in HTML
<p ng-bind-html="safeInput"></p>
Why? $sanitize removes dangerous scripts while keeping safe HTML elements.
D. Validate and Escape Input on the Backend
Even if AngularJS protects the frontend, always validate user input on the server to prevent stored XSS.
Escape HTML Special Characters in Server-side Code
- Node.js (Express)
const escapeHtml = require('escape-html'); app.post('/submit', (req, res) => { const safeInput = escapeHtml(req.body.userInput); // Store safeInput in the database }); - Python (Django)
from django.utils.html import escape safe_input = escape(user_input) - PHP
$safe_input = htmlspecialchars($_POST['userInput'], ENT_QUOTES, 'UTF-8');
E. Use Content Security Policy (CSP) to Prevent Script Execution
A strong CSP policy blocks inline scripts and external script injection.
Set a CSP Header in the Backend
Content-Security-Policy: default-src 'self'; script-src 'self'
Why? This prevents XSS by blocking scripts that don’t originate from your domain.
F. Prevent URL-Based XSS by Encoding URLs
If user-generated content is used in URLs, encode it to prevent injection.
Use $sce.trustAsResourceUrl() for Safe URLs
$scope.safeUrl = $sce.trustAsResourceUrl(userInputUrl);
Use Angular’s ng-href Instead of href
<a ng-href="{{ safeUrl }}">Click Here</a>
Avoid Using href Directly
<a href="{{ userInputUrl }}">Click Here</a> <!-- XSS Risk -->
