9.9 KiB
CSRF Protection Implementation
This document describes the comprehensive CSRF (Cross-Site Request Forgery) protection implemented in the LiveDash application.
Overview
CSRF protection has been implemented to prevent cross-site request forgery attacks on state-changing operations. The implementation follows industry best practices and provides protection at multiple layers:
- Middleware Level: Automatic CSRF validation for protected endpoints
- tRPC Level: CSRF protection for all state-changing tRPC procedures
- Client Level: Automatic token management and inclusion in requests
- Component Level: React components and hooks for easy integration
Implementation Components
1. Core CSRF Library (lib/csrf.ts)
The core CSRF functionality includes:
- Token Generation: Cryptographically secure token generation using the
csrflibrary - Token Verification: Server-side token validation
- Request Parsing: Support for tokens in headers, JSON bodies, and form data
- Client Utilities: Browser-side token management and request enhancement
Key Functions:
generateCSRFToken()- Creates new CSRF tokensverifyCSRFToken()- Validates tokens server-sideCSRFProtection.validateRequest()- Request validation middlewareCSRFClient.*- Client-side utilities
2. Middleware Protection (middleware/csrfProtection.ts)
Provides automatic CSRF protection for API endpoints:
Protected Endpoints:
/api/auth/*- Authentication endpoints/api/register- User registration/api/forgot-password- Password reset requests/api/reset-password- Password reset completion/api/dashboard/*- Dashboard API endpoints/api/platform/*- Platform admin endpoints/api/trpc/*- All tRPC endpoints
Protected Methods:
POST- Create operationsPUT- Update operationsDELETE- Delete operationsPATCH- Partial update operations
Safe Methods (Not Protected):
GET- Read operationsHEAD- Metadata requestsOPTIONS- CORS preflight requests
3. tRPC Integration (lib/trpc.ts)
CSRF protection integrated into tRPC procedures:
New Procedure Types:
csrfProtectedProcedure- Basic CSRF protectioncsrfProtectedAuthProcedure- CSRF + authentication protectioncsrfProtectedCompanyProcedure- CSRF + company access protectioncsrfProtectedAdminProcedure- CSRF + admin access protection
Updated Router Example:
// Before
register: rateLimitedProcedure
.input(registerSchema)
.mutation(async ({ input, ctx }) => { /* ... */ });
// After
register: csrfProtectedProcedure
.input(registerSchema)
.mutation(async ({ input, ctx }) => { /* ... */ });
4. Client-Side Integration
tRPC Client (lib/trpc-client.ts)
- Automatic CSRF token inclusion in tRPC requests
- Token extracted from cookies and added to request headers
React Hooks (lib/hooks/useCSRF.ts)
useCSRF()- Basic token managementuseCSRFFetch()- Enhanced fetch with automatic CSRF tokensuseCSRFForm()- Form submission with CSRF protection
Provider Component (components/providers/CSRFProvider.tsx)
- Application-wide CSRF token management
- Automatic token fetching and refresh
- Context-based token sharing
Protected Form Component (components/forms/CSRFProtectedForm.tsx)
- Ready-to-use form component with CSRF protection
- Automatic token inclusion in form submissions
- Graceful fallback for non-JavaScript environments
5. API Endpoint (app/api/csrf-token/route.ts)
Provides CSRF tokens to client applications:
GET /api/csrf-token- Returns new CSRF token- Sets HTTP-only cookie for automatic inclusion
- Used by client-side hooks and components
Configuration
Environment Variables
# CSRF Secret (optional - defaults to NEXTAUTH_SECRET)
CSRF_SECRET=your-csrf-secret-key
CSRF Configuration (lib/csrf.ts)
export const CSRF_CONFIG = {
cookieName: "csrf-token",
headerName: "x-csrf-token",
secret: env.CSRF_SECRET,
cookie: {
httpOnly: true,
secure: env.NODE_ENV === "production",
sameSite: "lax",
maxAge: 60 * 60 * 24, // 24 hours
},
};
Usage Examples
1. Using CSRF in React Components
import { useCSRFFetch } from '@/lib/hooks/useCSRF';
function MyComponent() {
const { csrfFetch } = useCSRFFetch();
const handleSubmit = async () => {
// CSRF token automatically included
const response = await csrfFetch('/api/dashboard/sessions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: 'example' }),
});
};
}
2. Using CSRF Protected Forms
import { CSRFProtectedForm } from '@/components/forms/CSRFProtectedForm';
function RegistrationForm() {
return (
<CSRFProtectedForm action="/api/register" method="POST">
<input name="email" type="email" required />
<input name="password" type="password" required />
<button type="submit">Register</button>
</CSRFProtectedForm>
);
}
3. Using CSRF in tRPC Procedures
// In your router file
export const userRouter = router({
updateProfile: csrfProtectedAuthProcedure
.input(userUpdateSchema)
.mutation(async ({ input, ctx }) => {
// CSRF validation automatically performed
// User authentication automatically verified
return updateUserProfile(input, ctx.user);
}),
});
4. Manual CSRF Token Handling
import { CSRFClient } from '@/lib/csrf';
// Get token from cookies
const token = CSRFClient.getToken();
// Add to fetch options
const options = CSRFClient.addTokenToFetch({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
// Add to form data
const formData = new FormData();
CSRFClient.addTokenToFormData(formData);
// Add to object
const dataWithToken = CSRFClient.addTokenToObject({ data: 'example' });
Security Features
1. Token Properties
- Cryptographically Secure: Uses the
csrflibrary with secure random generation - Short-Lived: 24-hour expiration by default
- HTTP-Only Cookies: Prevents XSS-based token theft
- SameSite Protection: Reduces CSRF attack surface
2. Validation Process
- Extract token from request (header, form data, or JSON body)
- Retrieve stored token from HTTP-only cookie
- Verify tokens match
- Validate token cryptographic integrity
- Allow or reject request based on validation
3. Error Handling
- Graceful Degradation: Form fallbacks for JavaScript-disabled browsers
- Clear Error Messages: Specific error codes for debugging
- Rate Limiting Integration: Works with existing auth rate limiting
- Logging: Comprehensive logging for security monitoring
Testing
Test Coverage
- Unit Tests: Token generation, validation, and client utilities
- Integration Tests: Middleware behavior and endpoint protection
- Component Tests: React hooks and form components
- End-to-End: Full request/response cycle testing
Running Tests
# Run all CSRF tests
pnpm test:vitest tests/unit/csrf*.test.ts tests/integration/csrf*.test.ts
# Run specific test files
pnpm test:vitest tests/unit/csrf.test.ts
pnpm test:vitest tests/integration/csrf-protection.test.ts
pnpm test:vitest tests/unit/csrf-hooks.test.tsx
Monitoring and Debugging
CSRF Validation Logs
Failed CSRF validations are logged with details:
CSRF validation failed for POST /api/dashboard/sessions: CSRF token missing from request
Common Issues and Solutions
-
Token Missing from Request
- Ensure CSRFProvider is wrapping your app
- Check that hooks are being used correctly
- Verify network requests include credentials
-
Token Mismatch
- Clear browser cookies and refresh
- Check for multiple token sources conflicting
- Verify server and client time synchronization
-
Integration Issues
- Ensure middleware is properly configured
- Check tRPC client configuration
- Verify protected procedures are using correct types
Migration Guide
For Existing Endpoints
-
Update tRPC procedures to use CSRF-protected variants:
// Old someAction: protectedProcedure.mutation(...) // New someAction: csrfProtectedAuthProcedure.mutation(...) -
Update client components to use CSRF hooks:
// Old const { data, mutate } = trpc.user.update.useMutation(); // New - no changes needed, CSRF automatically handled const { data, mutate } = trpc.user.update.useMutation(); -
Update manual API calls to include CSRF tokens:
// Old fetch('/api/endpoint', { method: 'POST', ... }); // New const { csrfFetch } = useCSRFFetch(); csrfFetch('/api/endpoint', { method: 'POST', ... });
Performance Considerations
- Minimal Overhead: Token validation adds ~1ms per request
- Efficient Caching: Tokens cached in memory and cookies
- Selective Protection: Only state-changing operations protected
- Optimized Parsing: Smart content-type detection for token extraction
Security Best Practices
- Always use HTTPS in production - CSRF tokens should never be transmitted over HTTP
- Monitor CSRF failures - Implement alerting for unusual CSRF failure patterns
- Regular secret rotation - Consider rotating CSRF secrets periodically
- Validate referrer headers - Additional protection layer (not implemented but recommended)
- Content Security Policy - Use CSP headers to prevent XSS attacks that could steal tokens
Conclusion
The CSRF protection implementation provides comprehensive defense against cross-site request forgery attacks while maintaining ease of use for developers. The multi-layer approach ensures protection at the middleware, application, and component levels, with automatic token management reducing the risk of developer error.
For questions or issues related to CSRF protection, refer to the test files for examples and the security documentation for additional context.