Module Overview
Estimated Time: 3-4 hours | Difficulty: Advanced | Prerequisites: Module 13
- XSS protection
- CSRF/XSRF protection
- Content Security Policy
- Authentication patterns
- Secure HTTP practices
- Input validation
Angular Security Model
XSS Protection
Angular automatically escapes all values bound to the DOM. This is not optional — it happens on every binding, every render cycle. You cannot accidentally disable it. This single feature prevents the vast majority of XSS attacks that plague vanilla JavaScript and jQuery applications.Automatic Sanitization
Bypassing Sanitization (Use with Caution!)
Safe HTML Pipe
CSRF/XSRF Protection
CSRF (Cross-Site Request Forgery) is an attack where a malicious website tricks the user’s browser into making authenticated requests to your API. For example, if a user is logged into their banking app and visits a malicious page, that page could submit a hidden form tobank.com/transfer?to=attacker&amount=10000. The browser automatically attaches the bank’s session cookies, so the request looks legitimate.
The defense: the server generates a unique token and sends it as a cookie. Angular’s HttpClient reads the cookie and sends the token back as a header. Since the malicious site cannot read cross-origin cookies, it cannot forge the header.
HttpClient XSRF Support
Content Security Policy
Configure CSP Headers
Nonce-based CSP (More Secure)
Authentication Patterns
JWT Authentication
Token storage matters more than you think. Storing JWTs in
localStorage is convenient but dangerous — any XSS vulnerability gives an attacker permanent access to the token. Storing the access token in memory (a JavaScript variable/signal) and the refresh token in an httpOnly cookie is the most secure pattern. The trade-off: the user must re-authenticate if they refresh the page (unless you use a refresh token flow). For most applications, this is worth the security improvement.Auth Interceptor
Route Guards
Secure HTTP Practices
HTTPS Enforcement
Secure Cookie Configuration
API Security Headers
Input Validation
Client-Side Validation
Server-Side Validation (Always Required!)
Security Checklist
Practice Exercise
Exercise: Implement Secure Authentication Flow
Build a secure authentication system with:
- Login/logout functionality
- JWT token handling (access + refresh)
- Protected routes
- Role-based access control
- XSS-safe user profile display
Solution
Solution
Summary
1
XSS Protection
Angular sanitizes by default; never bypass for user input
2
CSRF Protection
Use Angular’s built-in XSRF support with proper server setup
3
Authentication
Implement secure token handling with refresh flow
4
Authorization
Use route guards and verify permissions server-side
5
Input Validation
Validate on both client and server; never trust client
Interview Deep-Dive
Q: A developer uses bypassSecurityTrustHtml to render user-submitted HTML from a CMS. Why is this dangerous, and how would you handle it safely?
Q: A developer uses bypassSecurityTrustHtml to render user-submitted HTML from a CMS. Why is this dangerous, and how would you handle it safely?
Strong Answer: bypassSecurityTrustHtml disables Angular’s XSS sanitization entirely for that content. If the CMS stores user-submitted HTML containing a script tag or an onerror handler, that code executes in every user’s browser — a textbook stored XSS vulnerability.The safe approach: sanitize on the server when content is submitted (DOMPurify, sanitize-html). Sanitize on the client using an allowlist of safe tags (p, strong, em, a, ul, li) and safe attributes (href, class, alt). Implement a Content Security Policy header that blocks inline script execution as defense-in-depth.Angular’s built-in sanitizer on [innerHTML] removes script tags and event handlers by default. For high-security apps, add DOMPurify on top, as it is actively maintained against the latest XSS vectors.Follow-up: Is [innerHTML] without bypass safe enough?
Answer: Angular’s sanitizer is good but not perfect — edge cases with obfuscated HTML exist. For anything that renders user-generated content, I add DOMPurify with a strict tag allowlist in addition to Angular’s sanitizer. Belt and suspenders.
Q: Where should you store JWT tokens in a browser-based Angular app? Explain the tradeoffs.
Q: Where should you store JWT tokens in a browser-based Angular app? Explain the tradeoffs.
Strong Answer: localStorage is persistent and accessible via JavaScript — vulnerable to XSS. httpOnly cookies are not accessible via JavaScript — resistant to XSS but vulnerable to CSRF (mitigated with SameSite=Strict and CSRF tokens). In-memory storage (a signal in AuthService) is cleared on refresh and not accessible to XSS, but requires re-authentication on page reload.My recommended approach: refresh token in an httpOnly, Secure, SameSite=Strict cookie set by the server. Short-lived access token in memory only. On page load, silently call the refresh endpoint. This resists both XSS (access token not in storage) and CSRF (SameSite=Strict).Follow-up: How do you handle multiple tabs?
Answer: Each tab gets its own in-memory access token via the shared refresh cookie. For coordinating logout across tabs, use the BroadcastChannel API — when one tab logs out, it broadcasts a “logout” event that other tabs receive.
Q: Your app has route guards protecting admin pages. A pen tester bypasses them by calling your API directly. What went wrong?
Q: Your app has route guards protecting admin pages. A pen tester bypasses them by calling your API directly. What went wrong?
Strong Answer: Nothing went wrong with the guards — they are a UX feature, not a security feature. Guards run in the browser and can be trivially bypassed. The real issue is missing server-side authorization on the API endpoints.Every API endpoint must independently verify the user’s identity and permissions. The JWT should contain the user’s role, and the server must check it on every request. Route guards redirect unauthorized users to a clean “forbidden” page instead of showing a broken admin UI. They do not prevent access — they prevent confusion.Follow-up: What about hiding admin UI elements with @if based on role?
Answer: Also UX, not security. The HTML is not rendered, but all component code IS in the JavaScript bundle. For true code-level protection, lazy-load admin features behind a route with canMatch that checks the role — the admin JavaScript is not even downloaded unless the JWT proves admin status. But the API must still enforce authorization independently.
Next Steps
Next: Capstone Project
Apply everything you’ve learned in a comprehensive project