Preventing XSS Attacks in React Applications

Preventing XSS Attacks in React Applications

Aymen Isfiaya
October 15, 2023
4 min read

Preventing XSS Attacks in React Applications

As a React developer, you build dynamic, user-friendly interfaces but without proper safeguards, your app could be vulnerable to Cross-Site Scripting (XSS) attacks.

XSS occurs when attackers inject malicious scripts into your app, which then execute in users browsers. This can lead to:

  • Stolen session cookies
  • Hijacked user accounts
  • Defaced websites

Good news: React has built-in protections, but you need to reinforce them. In this guide, you'll learn:

  • How XSS works in React
  • React's built-in XSS defenses
  • Proactive prevention techniques
  • Code examples for secure apps

How XSS Works in React

Common XSS Attack Vectors

Dangerously Set Inner HTML

If you render unsanitized HTML, embedded scripts run:

// Vulnerable code
function UserBio({ bio }) {
  return <div dangerouslySetInnerHTML={{ __html: bio }} />;
}

// If `bio` contains <script>maliciousCode()</script>, it executes!

URL Injection

// Vulnerable code
<a href="javascript:alert('Hacked!')">Click Me</a>

Third-Party Library Risks

Some npm packages may contain unsafe rendering.

React's Built-in XSS Protections

Automatic Escaping in JSX

React escapes all variables rendered in {} by default:

// Safe: User input is treated as text, not HTML
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
  // If `name` is "<script>alert(1)</script>", it won't execute!
}

No innerHTML Equivalent by Default

React requires explicit use of dangerouslySetInnerHTML to render raw HTML, reminding developers of risks.

Proactive XSS Prevention in React

Sanitize Dynamic Content

Use DOMPurify to clean HTML before rendering:

import DOMPurify from 'dompurify';

function SafeHTML({ html }) {
  const clean = DOMPurify.sanitize(html);
  return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}

Avoid dangerouslySetInnerHTML When Possible

Prefer React components over raw HTML:

// ❌ Risky
<div dangerouslySetInnerHTML={{ __html: userContent }} />

// βœ… Safer (if HTML isn't needed)
<div>{userContent}</div>

Secure URL Handling

Sanitize dynamic URLs to prevent javascript: attacks:

function SafeLink({ url, children }) {
  const isSafe = url.startsWith('http://') || url.startsWith('https://');
  return <a href={isSafe ? url : '#'}>{children}</a>;
}

Use HTTP-Only Cookies for Sessions

Prevent cookie theft via XSS:

// Back-end should set cookies with:
Set-Cookie: sessionId=123; HttpOnly; Secure

Implement CSP (Content Security Policy)

Add a CSP header to block inline scripts:

Content-Security-Policy: script-src 'self' https://trusted-cdn.com;

Advanced Protections

Use Trusted Libraries for Markdown/Rich Text

Instead of rendering raw HTML, use:

  • react-markdown (for Markdown)
  • sanitize-html (for custom HTML)

Escape Data in HTTP Responses

Ensure your back-end API escapes JSON responses:

// Node.js example (using `he` library)
import he from 'he';
res.json({ bio: he.encode(user.bio) });

Real-World React XSS Scenarios

Scenario 1: Rendering User-Generated Content

import DOMPurify from 'dompurify';

function UserComment({ comment }) {
  return (
    <div
      dangerouslySetInnerHTML={{
        __html: DOMPurify.sanitize(comment),
      }}
    />
  );
}

Scenario 2: Dynamic Styling (Avoid eval-like Risks)

// ❌ Unsafe (eval-like behavior)
<div style={{ background: userInput }} />;

// βœ… Safer (validate input first)
const isValidColor = color => /^#[0-9A-F]{6}$/i.test(color);

<div style={{ background: isValidColor(userInput) ? userInput : '#fff' }} />;

Key Takeaways

DoDon't
Use DOMPurify for HTMLTrust raw innerHTML
Escape dynamic URLsAllow javascript: links
Prefer text over HTML renderingUse eval() or new Function()
Enable CSP headersIgnore third-party library risks

Conclusion

React reduces XSS risks but doesn't eliminate them. To build truly secure apps:

  • Sanitize all dynamic content
  • Avoid dangerouslySetInnerHTML unless necessary
  • Use CSP and HttpOnly cookies

By following these practices, you'll shield your React apps from XSS attacks. πŸ›‘οΈ

Related Articles