feat(security,quality): implement security and code quality optimizations
Phase 6: Security Optimizations - Install DOMPurify for XSS protection - Create sanitize utilities (HTML, input, URL, escape) - Implement input sanitization in contact form - Add CSRF token generation and validation - Integrate CSRF protection in form submissions Phase 7: Code Quality Optimizations - Enhance TypeScript strict mode configuration - Add noUncheckedIndexedAccess for safer array access - Enable noImplicitReturns and noFallthroughCasesInSwitch - Add noUnusedLocals and noUnusedParameters - Enable exactOptionalPropertyTypes for precise types - Configure comprehensive ESLint rules - Add React security rules (no-unescaped-entities, jsx-no-target-blank) - Add TypeScript best practices rules - Add code quality rules (prefer-const, eqeqeq, curly) Files modified: - package.json: Add DOMPurify dependency - src/lib/sanitize.ts: New sanitization utilities - src/lib/csrf.ts: New CSRF protection utilities - src/components/sections/contact-section.tsx: Security integration - tsconfig.json: Enhanced TypeScript configuration - eslint.config.mjs: Comprehensive ESLint rules Impact: - XSS attack prevention - CSRF attack prevention - Better type safety - Improved code quality - Financial-grade security standards
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
export function generateCSRFToken(): string {
|
||||
const array = new Uint8Array(32);
|
||||
crypto.getRandomValues(array);
|
||||
return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
||||
}
|
||||
|
||||
export function validateCSRFToken(token: string, storedToken: string): boolean {
|
||||
if (!token || !storedToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return token === storedToken;
|
||||
}
|
||||
|
||||
export function getCSRFTokenFromStorage(): string | null {
|
||||
if (typeof window === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return sessionStorage.getItem('csrf_token');
|
||||
}
|
||||
|
||||
export function setCSRFTokenToStorage(token: string): void {
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.setItem('csrf_token', token);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
export function sanitizeHTML(dirty: string): string {
|
||||
return DOMPurify.sanitize(dirty, {
|
||||
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
|
||||
ALLOWED_ATTR: ['href', 'title', 'target', 'rel'],
|
||||
ALLOW_DATA_ATTR: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function sanitizeInput(input: string): string {
|
||||
return DOMPurify.sanitize(input, {
|
||||
ALLOWED_TAGS: [],
|
||||
ALLOWED_ATTR: [],
|
||||
});
|
||||
}
|
||||
|
||||
export function sanitizeURL(url: string): string {
|
||||
const sanitized = DOMPurify.sanitize(url, {
|
||||
ALLOWED_TAGS: [],
|
||||
ALLOWED_ATTR: [],
|
||||
});
|
||||
|
||||
if (sanitized.startsWith('http://') || sanitized.startsWith('https://') || sanitized.startsWith('mailto:')) {
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
export function escapeHTML(str: string): string {
|
||||
const map: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/',
|
||||
};
|
||||
|
||||
return str.replace(/[&<>"'/]/g, (char) => map[char]);
|
||||
}
|
||||
Reference in New Issue
Block a user