3e5e135b47
- 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
5.4 KiB
5.4 KiB
XSS Protection Usage Examples
Basic Usage
Sanitizing Text Content
import { sanitizeText } from "@/lib/sanitize";
// In a component
function MyComponent({ cmsData }) {
return (
<div>
<h1>{sanitizeText(cmsData.title)}</h1>
<p>{sanitizeText(cmsData.description)}</p>
</div>
);
}
Sanitizing URLs
import { sanitizeUrl } from "@/lib/sanitize";
import Link from "next/link";
import Image from "next/image";
function MyComponent({ cmsData }) {
return (
<div>
{/* For links */}
<Link href={sanitizeUrl(cmsData.link) || "#"}>Click here</Link>
{/* For images */}
<Image
src={sanitizeUrl(cmsData.imageUrl) || "/fallback.svg"}
alt={sanitizeText(cmsData.imageAlt)}
width={100}
height={100}
/>
</div>
);
}
Sanitizing HTML Content
import { sanitizeHtml } from "@/lib/sanitize";
function MyComponent({ cmsData }) {
return (
<div>
{/* With default allowed tags (b, i, em, strong, a, br, p) */}
<div
dangerouslySetInnerHTML={{
__html: sanitizeHtml(cmsData.richContent),
}}
/>
{/* With custom allowed tags */}
<div
dangerouslySetInnerHTML={{
__html: sanitizeHtml(cmsData.richContent, ["p", "br", "strong"]),
}}
/>
</div>
);
}
Real-World Examples
Example 1: Dynamic Marketing Page
import { sanitizeText, sanitizeUrl } from "@/lib/sanitize";
export default function MarketingPage({ cmsData }) {
return (
<main>
<section>
<h1>{sanitizeText(cmsData.hero.title)}</h1>
<p>{sanitizeText(cmsData.hero.description)}</p>
<Link href={sanitizeUrl(cmsData.hero.buttonLink) || "#"}>
{sanitizeText(cmsData.hero.buttonText)}
</Link>
</section>
<section>
{cmsData.features.map((feature) => (
<article key={feature.id}>
<Image
src={sanitizeUrl(feature.icon) || "/default-icon.svg"}
alt={sanitizeText(feature.title)}
width={48}
height={48}
/>
<h3>{sanitizeText(feature.title)}</h3>
<p>{sanitizeText(feature.description)}</p>
</article>
))}
</section>
</main>
);
}
Example 2: Dynamic Form Fields
import { sanitizeText } from "@/lib/sanitize";
import { useForm } from "react-hook-form";
export default function DynamicForm({ contactData }) {
const { register, handleSubmit } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
{contactData.fields.map((field) => (
<div key={field.name}>
<label htmlFor={field.name}>{sanitizeText(field.label)}</label>
<input
id={field.name}
placeholder={sanitizeText(field.placeholder)}
{...register(field.name)}
/>
</div>
))}
<button type="submit">
{sanitizeText(contactData.submitButtonText)}
</button>
</form>
);
}
Example 3: User-Generated Content
import { sanitizeHtml } from "@/lib/sanitize";
export default function CommentSection({ comments }) {
return (
<div>
{comments.map((comment) => (
<article key={comment.id}>
<h4>{sanitizeText(comment.author)}</h4>
{/* Allow only basic formatting tags */}
<div
dangerouslySetInnerHTML={{
__html: sanitizeHtml(comment.content, [
"p",
"br",
"em",
"strong",
]),
}}
/>
</article>
))}
</div>
);
}
Common XSS Attack Vectors (All Blocked)
// These malicious inputs will be sanitized:
// 1. Script injection
const xss1 = "<script>alert('XSS')</script>";
sanitizeText(xss1); // Safe: <script>alert('XSS')</script>
// 2. Event handler injection
const xss2 = "<img src=x onerror=alert('XSS')>";
sanitizeText(xss2); // Safe: <img src=x onerror=alert('XSS')>
// 3. JavaScript URL
const xss3 = "javascript:alert('XSS')";
sanitizeUrl(xss3); // Returns: ""
// 4. Data URL with script
const xss4 = "data:text/html,<script>alert('XSS')</script>";
sanitizeUrl(xss4); // Returns: ""
// 5. Iframe injection
const xss5 = "<iframe src='javascript:alert(1)'></iframe>";
sanitizeText(xss5); // Safe: <iframe src='javascript:alert(1)'></iframe>
Best Practices
- Always sanitize external data before rendering
- Use the appropriate function for the content type
- Provide fallback values for URLs and optional content
- Never trust user input or external API data
- Keep dependencies updated to get latest security patches
When NOT to Sanitize
- Static content defined in your codebase
- Environment variables (but validate them)
- Data from trusted internal APIs (but still validate)
- Constants and configuration values
Testing Your Sanitization
// Test with malicious input
const testData = {
title: "<script>alert('XSS')</script>Hello",
link: "javascript:alert('XSS')",
description: "<img src=x onerror=alert('XSS')>",
};
// All should be safe
console.log(sanitizeText(testData.title)); // No script execution
console.log(sanitizeUrl(testData.link)); // Empty string
console.log(sanitizeText(testData.description)); // No image/script