- Add sanitize.ts utility module with sanitizeText(), sanitizeUrl(), and sanitizeHtml() functions - Implement server-side HTML entity escaping and client-side DOMPurify sanitization - Add comprehensive test suite for sanitization functions in lib/__tests__/sanitize.test.ts - Secure marketing pages by sanitizing all CMS data (hero, features, challenges, advantages, footer) - Secure inquiries form by sanitizing field labels, placeholders, and button text - Add SECURITY.md documentation outlining XSS protection measures and best practices - Add USAGE_EXAMPLES.md with detailed examples of sanitization function usage - Add XSS_PROTECTION_SUMMARY.md with implementation overview - Update package.json to include dompurify (^3.3.0) dependency - Protects against common XSS attack vectors including script injection, event handlers, and malicious URLs
3.2 KiB
Security - XSS Protection
This document outlines the XSS (Cross-Site Scripting) protection measures implemented in this application.
Overview
All external data from the CMS API is sanitized using DOMPurify before being rendered to prevent XSS attacks.
Sanitization Functions
Located in lib/sanitize.ts:
sanitizeText()
Strips all HTML tags from text. Use this for plain text content that should never contain HTML.
import { sanitizeText } from "@/lib/sanitize";
// Example usage
<h1>{sanitizeText(cmsData?.title)}</h1>;
sanitizeHtml()
Allows specific HTML tags while removing dangerous content. Use this when you need to render formatted text.
import { sanitizeHtml } from "@/lib/sanitize";
// Example usage with default allowed tags (b, i, em, strong, a, br, p)
<div dangerouslySetInnerHTML={{ __html: sanitizeHtml(cmsData?.content) }} />
// Example with custom allowed tags
<div dangerouslySetInnerHTML={{ __html: sanitizeHtml(cmsData?.content, ["p", "br"]) }} />
sanitizeUrl()
Sanitizes URLs to prevent javascript:, data:, and vbscript: URI attacks.
import { sanitizeUrl } from "@/lib/sanitize";
// Example usage
<Link href={sanitizeUrl(cmsData?.link) || "#"}>Click here</Link>
<Image src={sanitizeUrl(cmsData?.imageUrl) || "/fallback.svg"} />
Protected Areas
The following components have been secured:
-
Marketing Pages (
app/marketing/[id]/page.tsx)- Hero section (title, description, button text, links)
- Features section (titles, descriptions, icons)
- Challenges section (titles, descriptions, icons)
- Advantages section (titles, descriptions, icons)
- Footer (email, phone, location, tagline, copyright)
-
Inquiries Form (
app/_inquires/form.tsx,app/_inquires/page.tsx)- Form field labels and placeholders
- Submit button text
- Section titles and descriptions
Best Practices
- Always sanitize external data - Any data from APIs, databases, or user input should be sanitized
- Use the right function - Use
sanitizeText()for plain text,sanitizeUrl()for URLs, andsanitizeHtml()for formatted content - Validate on the server - While client-side sanitization helps, always validate and sanitize on the server as well
- Keep DOMPurify updated - Regularly update the DOMPurify package to get the latest security fixes
Server-Side Rendering
The sanitization functions work in both client and server environments:
- Server-side: Uses HTML entity escaping to prevent XSS attacks
- Client-side: Uses DOMPurify for advanced HTML sanitization
This hybrid approach ensures:
- Fast server-side rendering without heavy dependencies
- Robust client-side protection with DOMPurify
- No build issues with Node.js-specific modules
Dependencies
dompurify(^3.3.0) - HTML sanitization library (client-side only)
Testing XSS Protection
To verify XSS protection is working, try injecting malicious content through the CMS:
// These should be sanitized and rendered harmless:
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
javascript:alert('XSS')
<iframe src="javascript:alert('XSS')"></iframe>
All of these should be stripped or neutralized by the sanitization functions.