服务端阅读 02月21日 16:11
如何测试和验证 CSRF 防护措施的有效性?
CSRF 攻击的测试和验证是确保防护措施有效性的重要环节,通过系统化的测试可以发现潜在的安全漏洞。CSRF 攻击测试方法1. 手动测试基本测试步骤准备测试环境:登录目标应用打开浏览器开发者工具记录 Cookie 和 Session 信息构造恶意请求:<!-- 测试页面 --><!DOCTYPE html><html><head> <title>CSRF Test</title></head><body> <h1>CSRF Attack Test</h1> <form id="csrfForm" action="https://target-site.com/api/transfer" method="POST"> <input type="hidden" name="to" value="attacker"> <input type="hidden" name="amount" value="100"> </form> <button onclick="document.getElementById('csrfForm').submit()">Test CSRF</button></body></html>验证攻击结果:检查请求是否成功查看服务器响应确认是否执行了恶意操作2. 自动化测试使用 Burp Suite# Burp Suite CSRF Token 检测脚本from burp import IBurpExtenderfrom burp import IHttpListenerclass BurpExtender(IBurpExtender, IHttpListener): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks self._helpers = callbacks.getHelpers() callbacks.registerHttpListener(self) def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): if messageIsRequest: request = messageInfo.getRequest() analyzedRequest = self._helpers.analyzeRequest(request) # 检查是否缺少 CSRF Token headers = analyzedRequest.getHeaders() hasCSRFToken = any('csrf' in header.lower() for header in headers) if not hasCSRFToken and analyzedRequest.getMethod() in ['POST', 'PUT', 'DELETE']: print(f"Potential CSRF vulnerability: {analyzedRequest.getUrl()}")使用 OWASP ZAP# 使用 OWASP ZAP 进行 CSRF 扫描zap-cli quick-scan --self-contained --start-options '-config api.disablekey=true' \ --spider -r csrf_report.html https://target-site.com3. 单元测试CSRF Token 验证测试// Jest 测试示例describe('CSRF Protection', () => { let app; let csrfToken; beforeAll(async () => { app = require('./app'); // 获取 CSRF Token const response = await request(app).get('/api/csrf-token'); csrfToken = response.body.csrfToken; }); test('应该拒绝没有 CSRF Token 的 POST 请求', async () => { const response = await request(app) .post('/api/submit') .send({ data: 'test' }); expect(response.status).toBe(403); expect(response.body.error).toContain('CSRF'); }); test('应该拒绝无效的 CSRF Token', async () => { const response = await request(app) .post('/api/submit') .set('X-CSRF-Token', 'invalid-token') .send({ data: 'test' }); expect(response.status).toBe(403); }); test('应该接受有效的 CSRF Token', async () => { const response = await request(app) .post('/api/submit') .set('X-CSRF-Token', csrfToken) .send({ data: 'test' }); expect(response.status).toBe(200); });});4. 集成测试端到端 CSRF 测试// Cypress 测试示例describe('CSRF Protection E2E', () => { beforeEach(() => { cy.login('testuser', 'password'); }); it('应该防止跨站请求伪造', () => { // 访问恶意网站模拟页面 cy.visit('http://malicious-site.com/csrf-test.html'); // 点击触发 CSRF 攻击的按钮 cy.get('button').click(); // 验证请求被阻止 cy.on('window:alert', (str) => { expect(str).to.include('forbidden'); }); }); it('应该允许同站请求', () => { cy.visit('/protected-page'); // 获取 CSRF Token cy.get('meta[name="csrf-token"]').should('have.attr', 'content'); // 提交表单 cy.get('form').submit(); // 验证请求成功 cy.contains('Success').should('be.visible'); });});防护措施验证1. CSRF Token 验证// 验证 CSRF Token 的实现function validateCSRFTokenImplementation(app) { const tests = [ { name: 'Token 应该是随机且不可预测的', test: async () => { const tokens = []; for (let i = 0; i < 100; i++) { const response = await request(app).get('/api/csrf-token'); tokens.push(response.body.csrfToken); } const uniqueTokens = new Set(tokens); return uniqueTokens.size === 100; } }, { name: 'Token 应该有足够的长度', test: async () => { const response = await request(app).get('/api/csrf-token'); return response.body.csrfToken.length >= 32; } }, { name: 'Token 应该有时效性', test: async () => { const response1 = await request(app).get('/api/csrf-token'); const token1 = response1.body.csrfToken; // 等待 Token 过期 await new Promise(resolve => setTimeout(resolve, 3600000)); const response2 = await request(app).get('/api/csrf-token'); const token2 = response2.body.csrfToken; return token1 !== token2; } } ]; return Promise.all(tests.map(async test => { const result = await test.test(); console.log(`${test.name}: ${result ? 'PASS' : 'FAIL'}`); return result; }));}2. SameSite Cookie 验证// 验证 SameSite Cookie 设置function validateSameSiteCookie(response) { const cookies = response.headers['set-cookie']; if (!cookies) { return false; } return cookies.some(cookie => { return cookie.includes('SameSite=') && (cookie.includes('SameSite=Strict') || cookie.includes('SameSite=Lax')); });}3. Referer 头验证// 验证 Referer 头检查async function testRefererValidation(app) { // 测试没有 Referer 的请求 const response1 = await request(app) .post('/api/submit') .set('Referer', '') .send({ data: 'test' }); if (response1.status !== 403) { console.log('FAIL: Should reject requests without Referer'); return false; } // 测试无效的 Referer const response2 = await request(app) .post('/api/submit') .set('Referer', 'https://malicious-site.com') .send({ data: 'test' }); if (response2.status !== 403) { console.log('FAIL: Should reject requests with invalid Referer'); return false; } // 测试有效的 Referer const response3 = await request(app) .post('/api/submit') .set('Referer', 'https://target-site.com') .send({ data: 'test' }); if (response3.status === 403) { console.log('FAIL: Should accept requests with valid Referer'); return false; } console.log('PASS: Referer validation working correctly'); return true;}渗透测试工具1. 使用 Metasploit# 使用 Metasploit 的 CSRF 模块msfconsoleuse auxiliary/http/csrf_testset RHOSTS target-site.comset RPORT 443set SSL trueexploit2. 使用 CSRFTester# CSRFTester 工具使用java -jar CSRFTester.jar# 导出测试报告测试报告测试报告模板# CSRF 安全测试报告## 测试概述- 测试日期: 2024-01-15- 测试人员: Security Team- 测试范围: Web Application## 测试方法1. 手动测试2. 自动化扫描3. 代码审查4. 渗透测试## 测试结果### 发现的漏洞| 漏洞类型 | 严重程度 | 状态 ||---------|---------|------|| 缺少 CSRF Token | 高 | 已修复 || SameSite Cookie 未设置 | 中 | 已修复 || Referer 验证缺失 | 中 | 待修复 |### 防护措施验证- CSRF Token: ✅ 通过- SameSite Cookie: ✅ 通过- Referer 验证: ⚠️ 部分通过- 双重提交 Cookie: ❌ 未实施## 建议1. 实施双重提交 Cookie2. 加强 Referer 验证3. 定期进行安全测试CSRF 攻击测试应该作为安全开发生命周期(SDLC)的一部分,定期进行以确保防护措施的有效性。