5月29日 22:54
What security issues should be noted when using axios? How to prevent XSS, CSRF, and other attacks?
When using axios for HTTP requests, you need to pay attention to various security issues, including XSS, CSRF, sensitive information leakage, etc.
1. XSS (Cross-Site Scripting) Protection
Problem Description
XSS attacks may inject malicious scripts through axios response data.
Protection Measures
javascript// 1. Response data escaping import DOMPurify from 'dompurify'; axios.interceptors.response.use( (response) => { // XSS filtering for response data if (response.data && typeof response.data === 'object') { response.data = sanitizeData(response.data); } return response; } ); function sanitizeData(data) { if (typeof data === 'string') { return DOMPurify.sanitize(data); } if (Array.isArray(data)) { return data.map(sanitizeData); } if (typeof data === 'object' && data !== null) { return Object.keys(data).reduce((acc, key) => { acc[key] = sanitizeData(data[key]); return acc; }, {}); } return data; } // 2. Set secure Content-Type axios.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8'; // 3. Prevent JSON injection axios.interceptors.request.use( (config) => { if (config.data && typeof config.data === 'object') { // Ensure sending JSON, not executable JavaScript config.data = JSON.stringify(config.data); } return config; } );
2. CSRF (Cross-Site Request Forgery) Protection
Problem Description
Attackers induce users to perform unintended actions on authenticated websites.
Protection Measures
javascript// 1. Use CSRF Token const api = axios.create({ xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', withCredentials: true // Allow carrying cookies }); // 2. Manually add CSRF Token api.interceptors.request.use((config) => { // Get from meta tag const token = document.querySelector('meta[name="csrf-token"]')?.content; if (token) { config.headers['X-CSRF-Token'] = token; } // Or get from cookie const csrfToken = getCookie('csrfToken'); if (csrfToken) { config.headers['X-CSRF-Token'] = csrfToken; } return config; }); // 3. Double Cookie Verification api.interceptors.request.use((config) => { const sessionId = getCookie('sessionId'); const csrfToken = getCookie('csrfToken'); if (sessionId && csrfToken) { config.headers['X-CSRF-Token'] = csrfToken; // Verify token and session association } return config; }); // 4. SameSite Cookie Setting // Server setting: Set-Cookie: sessionId=xxx; SameSite=Strict; Secure; HttpOnly
3. Sensitive Information Protection
Token Secure Storage
javascript// ❌ Don't store directly in localStorage (XSS risk) localStorage.setItem('token', token); // ✅ Use httpOnly cookie (recommended) // Server setting: Set-Cookie: token=xxx; HttpOnly; Secure; SameSite=Strict // ✅ If must use localStorage, add additional security measures const secureStorage = { set(key, value) { // Add timestamp and signature const data = { value, timestamp: Date.now(), signature: generateSignature(value) }; localStorage.setItem(key, JSON.stringify(data)); }, get(key) { const item = localStorage.getItem(key); if (!item) return null; try { const data = JSON.parse(item); // Verify signature if (data.signature !== generateSignature(data.value)) { this.remove(key); return null; } // Check expiration (e.g., 24 hours) if (Date.now() - data.timestamp > 24 * 60 * 60 * 1000) { this.remove(key); return null; } return data.value; } catch { return null; } }, remove(key) { localStorage.removeItem(key); } }; function generateSignature(value) { // Use simple hash or HMAC return btoa(value + SECRET_KEY); }
Sensitive Information in Request Headers
javascript// 1. Avoid passing sensitive information in URL // ❌ Wrong axios.get(`/api/user?password=${password}`); // ✅ Correct axios.post('/api/user', { password }); // 2. Request header encryption import CryptoJS from 'crypto-js'; axios.interceptors.request.use((config) => { // Encrypt sensitive headers if (config.headers.Authorization) { config.headers['X-Encrypted'] = '1'; // Or use custom encryption // config.headers.Authorization = encrypt(config.headers.Authorization); } return config; }); // 3. Limit header exposure // Server setting: Access-Control-Expose-Headers: limited-headers
4. HTTPS and Certificate Verification
javascript// 1. Force HTTPS const api = axios.create({ baseURL: 'https://api.example.com', // Must use HTTPS }); // 2. Certificate verification in Node.js environment const https = require('https'); const fs = require('fs'); const api = axios.create({ httpsAgent: new https.Agent({ // Don't set to false in production rejectUnauthorized: true, // Use custom CA certificate ca: fs.readFileSync('path/to/ca-cert.pem') }) }); // 3. Certificate Pinning const httpsAgent = new https.Agent({ checkServerIdentity: (host, cert) => { const expectedFingerprint = 'AA:BB:CC:DD:EE:FF:...'; const actualFingerprint = cert.fingerprint256; if (actualFingerprint !== expectedFingerprint) { throw new Error('Certificate fingerprint mismatch'); } } });
5. Request Parameter Validation
javascriptimport Joi from 'joi'; // 1. Request parameter validation const requestSchema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().min(8).max(32).required(), age: Joi.number().integer().min(0).max(150) }); axios.interceptors.request.use((config) => { if (config.data) { const { error } = requestSchema.validate(config.data); if (error) { return Promise.reject(new Error(`Validation error: ${error.message}`)); } } return config; }); // 2. URL parameter encoding axios.interceptors.request.use((config) => { if (config.params) { config.params = Object.keys(config.params).reduce((acc, key) => { acc[key] = encodeURIComponent(config.params[key]); return acc; }, {}); } return config; }); // 3. Prevent SQL injection (frontend level) function sanitizeInput(input) { if (typeof input !== 'string') return input; // Remove or escape dangerous characters return input .replace(/[;\"']/g, '') .replace(/--/g, '') .replace(/\/\*/g, '') .replace(/\*\//g, ''); } axios.interceptors.request.use((config) => { if (config.data) { config.data = Object.keys(config.data).reduce((acc, key) => { acc[key] = sanitizeInput(config.data[key]); return acc; }, {}); } return config; });
6. Response Security Verification
javascript// 1. Verify response content type axios.interceptors.response.use( (response) => { const contentType = response.headers['content-type']; // Ensure response is JSON if (!contentType || !contentType.includes('application/json')) { return Promise.reject(new Error('Invalid content type')); } return response; } ); // 2. Verify response data signature axios.interceptors.response.use( (response) => { const signature = response.headers['x-response-signature']; const data = JSON.stringify(response.data); if (signature && !verifySignature(data, signature)) { return Promise.reject(new Error('Invalid response signature')); } return response; } ); function verifySignature(data, signature) { const expectedSignature = CryptoJS.HmacSHA256(data, SECRET_KEY).toString(); return signature === expectedSignature; }
7. Security Header Settings
javascript// Send security-related request headers const secureApi = axios.create({ headers: { // Prevent MIME type sniffing 'X-Content-Type-Options': 'nosniff', // Enable XSS filter 'X-XSS-Protection': '1; mode=block', // Clickjacking protection 'X-Frame-Options': 'DENY', // Content Security Policy 'Content-Security-Policy': "default-src 'self'", // Strict Transport Security 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains' } });
8. Logging and Monitoring
javascript// Security logging axios.interceptors.request.use((config) => { // Log request (excluding sensitive information) securityLogger.info({ type: 'request', url: config.url, method: config.method, timestamp: new Date().toISOString(), // Don't log sensitive information in headers or data }); return config; }); axios.interceptors.response.use( (response) => { securityLogger.info({ type: 'response', url: response.config.url, status: response.status, timestamp: new Date().toISOString() }); return response; }, (error) => { securityLogger.error({ type: 'error', url: error.config?.url, status: error.response?.status, message: error.message, timestamp: new Date().toISOString() }); return Promise.reject(error); } ); // Anomaly detection function detectAnomalies(response) { // Detect unusually large responses const responseSize = JSON.stringify(response.data).length; if (responseSize > 10 * 1024 * 1024) { // 10MB securityLogger.warn('Unusually large response detected'); } // Detect abnormal response times const duration = response.config.metadata?.duration; if (duration > 30000) { // 30 seconds securityLogger.warn('Slow response detected'); } }
9. Complete Security Configuration Example
javascriptimport axios from 'axios'; import DOMPurify from 'dompurify'; import CryptoJS from 'crypto-js'; const secureApi = axios.create({ baseURL: 'https://api.example.com', timeout: 10000, withCredentials: true, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', headers: { 'Content-Type': 'application/json; charset=utf-8', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block' } }); // Request interceptor - security processing secureApi.interceptors.request.use( (config) => { // 1. Parameter validation and sanitization if (config.data) { config.data = sanitizeData(config.data); } // 2. Add request signature const timestamp = Date.now(); config.headers['X-Timestamp'] = timestamp; config.headers['X-Signature'] = generateRequestSignature(config, timestamp); // 3. Log security event logSecurityEvent('request', config); return config; }, (error) => Promise.reject(error) ); // Response interceptor - security processing secureApi.interceptors.response.use( (response) => { // 1. Verify response signature if (!verifyResponseSignature(response)) { return Promise.reject(new Error('Invalid response signature')); } // 2. XSS sanitization if (response.data) { response.data = sanitizeData(response.data); } // 3. Anomaly detection detectAnomalies(response); return response; }, (error) => { logSecurityEvent('error', null, error); return Promise.reject(error); } ); export default secureApi;
Security Checklist
- Use HTTPS for all data transmission
- Enable CSRF protection
- Store sensitive information using httpOnly Cookie
- Validate and sanitize input data
- Filter output data for XSS
- Set appropriate security headers
- Implement request/response signature verification
- Log security events and monitor anomalies
- Regularly update dependency packages
- Conduct security audits and penetration testing