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
223 lines
5.4 KiB
Markdown
223 lines
5.4 KiB
Markdown
# XSS Protection Usage Examples
|
|
|
|
## Basic Usage
|
|
|
|
### Sanitizing Text Content
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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)
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
1. **Always sanitize external data** before rendering
|
|
2. **Use the appropriate function** for the content type
|
|
3. **Provide fallback values** for URLs and optional content
|
|
4. **Never trust user input** or external API data
|
|
5. **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
|
|
|
|
```typescript
|
|
// 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
|
|
```
|