1. 项目概述:为什么Web安全攻防是每个开发者的必修课
如果你是一名Web开发者,或者正在学习后端、前端技术,那么“Web安全”这四个字,绝对不应该只是简历上的一句套话。我见过太多项目,功能做得花里胡哨,上线后却因为一个简单的XSS(跨站脚本)漏洞被挂上黑页,或者因为CSRF(跨站请求伪造)漏洞导致用户资金被悄无声息地转走。这些事故的背后,往往不是技术有多高深,而是开发者对基础的安全机制缺乏敬畏和实操经验。今天,我们就抛开那些晦涩的理论,直接上手,用一个实战项目的视角,从最经典的XSS到CSRF,带你走一遍完整的攻防流程。你会发现,安全不是运维或安全工程师的专属,它应该是编码时的一种条件反射。
这个实战项目的核心目标很明确:亲手搭建一个存在漏洞的靶场环境,然后分别以攻击者和防御者的双重身份,去理解漏洞的原理、利用方式,并最终实现有效的防护。我们会使用DVWA(Damn Vulnerable Web Application)这个经典的漏洞练习平台作为实验环境,因为它集成了从低到高不同安全等级的漏洞场景,非常适合学习和复现。通过这个过程,你不仅能看懂那些安全报告里的术语,更能掌握在真实开发中如何写出更健壮的代码,以及如何在出现安全警报时,快速定位和修复问题。无论你是刚入门的新手,还是有一定经验想系统梳理安全知识的开发者,这篇内容都将是一份可以直接“抄作业”的实操指南。
2. 环境准备与靶场搭建:从零构建你的安全实验室
工欲善其事,必先利其器。在开始真正的攻防之前,一个稳定、隔离的测试环境是必不可少的。我强烈不建议你在任何生产服务器、甚至是个人的主力开发机上直接进行漏洞利用练习,一个误操作可能导致服务崩溃或数据丢失。最稳妥的方式是使用虚拟机。
2.1 虚拟机与靶场选择
我个人的首选是使用VirtualBox或VMware Workstation Player(免费版即可)来创建一台虚拟机。在虚拟机内部,我们安装一个集成了LAMP(Linux, Apache, MySQL, PHP)环境和漏洞靶场的系统。这里有两条高效的路径:
路径一:使用预构建的靶机镜像这是最快的方式。诸如Metasploitable 2、OWASP Broken Web Applications (OWASP BWA)或DVWA专用镜像都是极佳的选择。以DVWA为例,你可以直接搜索下载一个已经配置好Apache、PHP、MySQL和DVWA的虚拟机镜像文件(通常是.ova格式)。在VirtualBox中,直接“导入”这个.ova文件,启动虚拟机,就获得了一个开箱即用的漏洞环境。虚拟机的网络模式建议设置为“桥接网络”,这样你的物理机可以直接通过虚拟机的IP地址访问靶场,就像访问一台真实的局域网内服务器一样。
路径二:手动搭建LAMP + DVWA如果你想更深入地理解环境依赖,手动搭建是更好的学习过程。在一台全新的Ubuntu Server虚拟机中,依次执行以下命令:
# 更新系统包 sudo apt update && sudo apt upgrade -y # 安装Apache、MySQL、PHP及常用扩展 sudo apt install apache2 mysql-server php libapache2-mod-php php-mysql php-gd php-curl -y # 安装Git并克隆DVWA代码 sudo apt install git -y cd /var/www/html sudo git clone https://github.com/digininja/DVWA.git # 设置目录权限 sudo chown -R www-data:www-data /var/www/html/DVWA sudo chmod -R 755 /var/www/html/DVWA # 配置MySQL。运行安全脚本,设置root密码,并移除匿名用户等不安全配置。 sudo mysql_secure_installation # 接着登录MySQL,为DVWA创建数据库和用户 sudo mysql -u root -p # 在MySQL提示符下执行: CREATE DATABASE dvwa; CREATE USER 'dvwa_user'@'localhost' IDENTIFIED BY 'p@ssw0rd'; GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa_user'@'localhost'; FLUSH PRIVILEGES; EXIT; # 复制DVWA配置文件并修改数据库连接信息 cd /var/www/html/DVWA/config sudo cp config.inc.php.dist config.inc.php sudo nano config.inc.php # 找到如下行并进行修改: # $_DVWA[ 'db_user' ] = 'dvwa_user'; # $_DVWA[ 'db_password' ] = 'p@ssw0rd'; # $_DVWA[ 'db_database' ] = 'dvwa'; # 同时,将 `$_DVWA[ 'default_security_level' ]` 设置为 `low` 以便练习。完成上述步骤后,在物理机的浏览器中访问http://[你的虚拟机IP]/DVWA/setup.php。点击页面底部的“Create / Reset Database”按钮。如果一切顺利,页面将提示数据库创建成功。之后,你就可以使用默认账号(admin / password)登录http://[你的虚拟机IP]/DVWA开始实战了。
注意:手动搭建时,PHP版本可能与DVWA存在兼容性问题。如果遇到“PHP function allow_url_include is disabled”等错误,需要根据提示修改PHP配置文件(
php.ini),并重启Apache服务(sudo systemctl restart apache2)。这个过程本身也是学习Web环境配置的一部分。
2.2 安全等级设置与攻击者心态建立
登录DVWA后,在左侧菜单找到“DVWA Security”并点击。在这里,你可以设置应用程序的安全等级,从“Low”、“Medium”到“High”。我强烈建议你从“Low”等级开始。这个等级下,应用程序几乎没有任何防护,漏洞利用最简单直接,能让你最清晰地看到漏洞产生的原始形态和攻击原理。在理解了“Low”等级的攻防后,再逐步提升到“Medium”和“High”,去挑战那些增加了基础过滤和防护机制的场景,这样你能阶梯式地理解防御技术的演进。
在开始攻击前,还需要准备好攻击者的“武器库”。现代浏览器自带的“开发者工具”(F12打开)就是最强大的武器之一。我们将频繁使用到其中的“元素检查器”(Elements)来查看和修改页面DOM,使用“控制台”(Console)来执行JavaScript代码,以及使用“网络”(Network)标签页来观察和分析HTTP请求与响应。此外,为了更方便地构造和发送复杂的HTTP请求,我推荐安装一个叫Burp Suite Community Edition的代理工具。它的“Repeater”和“Intruder”功能在后续的CSRF攻击中会非常有用。简单来说,Burp Suite可以作为浏览器和服务器之间的一个代理,拦截、查看并修改所有经过的HTTP/HTTPS流量。
现在,你的安全实验室已经就绪。让我们戴上“黑帽子”,先从最常见的XSS漏洞开始,看看攻击者是如何利用它来作恶的。
3. XSS攻防实战:理解三种类型的跨站脚本攻击
XSS,全称跨站脚本攻击。它的核心原理是:攻击者能够将恶意脚本代码注入到可信的网站中,当其他用户浏览该网站时,浏览器会执行这些恶意脚本。根据恶意脚本注入和执行的上下文不同,XSS主要分为三类:反射型、存储型和DOM型。我们逐一攻破。
3.1 反射型XSS:一次性的“钓鱼”攻击
反射型XSS是最常见的一种。恶意脚本通常“反射”在URL参数中,服务器接收到这个参数后,未经过滤就直接将其拼接到HTTP响应里,返回给用户的浏览器执行。
攻击实战(DVWA Security: Low):
- 在DVWA左侧菜单点击“XSS reflected”。
- 你会看到一个简单的输入框,提示你输入名字。在“Low”安全等级下,尝试输入:``。点击“Submit”。
- 页面会直接弹出一个警告框,显示“XSS”。恭喜你,完成了一次最简单的反射型XSS攻击。
发生了什么?我们输入的被服务器直接接收,并原封不动地放入了返回的HTML页面中,可能类似于:`<pre>Hello, <script>alert('XSS')</script></pre>`。当浏览器渲染这段HTML时,遇到了标签,就会执行其中的JavaScript代码。
防御思路与实战(从Low到High):
- Low(无防御):服务器端没有任何过滤。
- Medium:DVWA尝试使用
str_replace函数将替换为空字符串。但这是非常脆弱的防御,我们可以轻松绕过,例如输入,过滤后中间的script被移除,剩下的字符拼接起来正好又形成了新的``标签。 - High:DVWA使用了更严格的正则表达式匹配,几乎过滤了所有已知的“script”标签变体。此时,传统的注入
标签的方式可能失效。**但反射型XSS的防御核心永远在服务器端**:对所有用户输入进行严格的输出编码或过滤。对于放入HTML上下文的变量,必须使用`htmlspecialchars()`函数(PHP)或类似函数进行转义,将`<`, `>`, `&`, `"`, `'` 等字符转换为HTML实体(如`<`变为`<`)。这样,即使用户输入了,最终输出的也是纯文本<script>alert('XSS')</script>,而不会被浏览器解析为标签。
3.2 存储型XSS:持久化的“网站寄生虫”
存储型XSS比反射型危害更大,因为恶意脚本被保存在了服务器端(如数据库、文件系统),所有访问特定页面的用户都会中招。常见于论坛评论、用户昵称、留言板等场景。
攻击实战(DVWA Security: Low):
- 点击“XSS stored”。
- 在“Name”和“Message”字段中,尝试输入包含恶意脚本的内容,例如在Message里输入:``。
- 提交后,你的“留言”就被存储了。之后任何用户(包括你自己)访问这个留言板页面时,页面都会执行弹窗脚本。
高级利用场景:弹窗只是演示。真实的攻击中,恶意脚本可能会:
- 窃取用户的会话Cookie(通过
document.cookie),攻击者从而能冒充用户登录。 - 将用户重定向到钓鱼网站。
- 在用户浏览器中发起其他恶意请求(如转账、发帖)。
防御实战:存储型XSS的防御需要输入验证和输出编码双管齐下。
- 输入验证:在服务器端接收数据时,就根据预期的数据类型进行严格校验。例如,名字字段应该只允许字母、数字和有限符号,拒绝任何HTML标签。可以使用白名单策略。
- 输出编码:同反射型XSS,在将数据从数据库取出、渲染到页面时,必须根据输出上下文进行编码。放入HTML就做HTML编码,放入JavaScript变量就做JavaScript编码,放入URL参数就做URL编码。
- 内容安全策略(CSP):这是一道强有力的浏览器端防线。通过在HTTP响应头中设置
Content-Security-Policy,你可以告诉浏览器只允许执行来自特定来源的脚本,从而即使有恶意脚本被注入,浏览器也不会执行。例如:Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com;表示只允许执行同源和指定CDN的脚本。
3.3 DOM型XSS:不经过服务器的客户端漏洞
DOM型XSS比较特殊,恶意数据的处理和脚本的执行完全发生在客户端的JavaScript中,服务器的响应可能本身是“干净”的。
攻击实战(原理模拟):假设有一段前端代码如下:
// 从URL的hash部分获取数据,并直接写入DOM var userInput = window.location.hash.substring(1); document.getElementById("output").innerHTML = "Welcome, " + userInput;如果攻击者构造一个URL:http://vulnerable-site.com/page.html#<img src=x onerror=alert('XSS')>。当用户访问这个链接时,userInput的值就是``,并被直接通过innerHTML插入到页面中,触发XSS。
防御实战:DOM型XSS的防御责任主要在前端。
- 避免使用危险的DOM操作:尽量避免使用
innerHTML、outerHTML、document.write()等可以直接插入HTML字符串的方法。优先使用textContent或innerText来设置纯文本内容。 - 如果必须使用,则必须编码:如果业务确实需要动态生成HTML,应使用安全的API来创建DOM节点(如
document.createElement,setAttribute),或者使用经过严格测试的模板引擎,它们通常会自动处理编码。 - 对来自非受信源的数据进行客户端校验和编码:即使是前端JavaScript从URL、Cookie或其他API获取的数据,在放入DOM前也要进行编码。
实操心得:在实际渗透测试或代码审计中,寻找XSS漏洞时,要关注所有“用户可控输入”的“输出点”。输入点包括:URL参数、POST表单、HTTP头(如User-Agent、Referer)、Cookie等。输出点包括:HTML正文、HTML属性、JavaScript代码段、CSS、URL等。用一个简单的payload如
或去测试每一个输入输出对,往往能快速发现低危漏洞。对于更复杂的过滤,需要结合混淆和编码技巧。
4. CSRF攻防实战:冒充用户的“隐身”请求
如果说XSS是利用了用户对网站的信任,那么CSRF(跨站请求伪造)则是利用了网站对用户浏览器的信任。攻击者诱骗受害者在已登录目标网站的情况下,访问一个恶意页面。这个恶意页面会自动向目标网站发起一个请求(如转账、改密码),因为浏览器会携带用户的Cookie,所以目标网站会认为这是用户的合法操作。
4.1 CSRF攻击原理与手动利用
理解CSRF的关键在于理解Web的会话管理机制。通常,用户登录后,服务器会下发一个Session ID,浏览器将其保存在Cookie中。此后,浏览器向该网站发起的每一个请求,都会自动带上这个Cookie。CSRF攻击正是滥用了这个“自动携带”机制。
攻击实战(DVWA Security: Low - CSRF):
- 在DVWA中,将安全等级设为“Low”,然后访问“CSRF”模块。
- 你会看到一个修改密码的页面,请求是GET方式,URL类似:
http://靶机IP/DVWA/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change。 - 攻击者构造一个恶意页面,其中包含一个自动加载的图片标签,其
src就是上述修改密码的URL:<html> <body> <img src="http://靶机IP/DVWA/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change" width="0" height="0" /> <h1>你被骗了!</h1> </body> </html> - 诱使已登录DVWA的用户访问这个恶意页面。用户的浏览器会尝试加载图片,从而自动向DVWA发起一个修改密码的GET请求。由于用户已登录,Cookie有效,密码就会被修改为“hacked”。
为什么能成功?
- 请求是由用户的浏览器发出的。
- 浏览器自动附带了用户的DVWA会话Cookie。
- 服务器端(Low等级)没有验证这个请求是否真正来自用户自愿发起的表单提交。
4.2 使用Burp Suite生成CSRF攻击POC
手动构造HTML页面比较麻烦。Burp Suite的“Generate CSRF PoC”功能可以一键完成。
- 配置浏览器代理指向Burp Suite(默认127.0.0.1:8080)。
- 在DVWA的CSRF页面(Low等级),输入新密码并点击“Change”,拦截这个请求。
- 在Burp Suite的Proxy -> Intercept标签页,右键点击拦截到的请求,选择“Engagement tools” -> “Generate CSRF PoC”。
- Burp Suite会弹出一个编辑器,里面已经生成好了包含恶意请求的HTML代码。你可以调整请求方式(GET/POST)、参数等。
- 点击“Copy HTML”或“Test in browser”,即可获得一个完整的攻击页面。将这个页面部署在攻击者的服务器上,诱骗受害者访问即可。
对于POST请求的CSRF:原理相同,只是恶意页面需要构造一个隐藏的form表单,并用JavaScript自动提交。Burp Suite生成的PoC同样可以处理POST请求。
4.3 CSRF的防御策略与实践
防御CSRF的核心思想是:让请求变得“不可预测”和“不可伪造”,确保它来自我们自己的应用页面。
1. 同源检测(校验Referer/Origin头)服务器可以检查HTTP请求头中的Referer或Origin字段,判断请求是否来自合法的源(即自己的网站域名)。这是一个简单有效的辅助手段,但并非绝对可靠,因为某些浏览器插件或网络环境可能会剥离这些头部,且存在被篡改的风险(尽管难度较大)。
2. 使用CSRF Token(最主流、最有效的方法)这是目前防御CSRF最推荐的方法。原理如下:
- 服务器在用户会话中生成一个随机、不可预测的令牌(Token),同时将其输出到表单中作为一个隐藏字段(
<input type="hidden" name="csrf_token" value="随机字符串">)。 - 当用户提交表单时,这个Token会随着其他数据一起提交到服务器。
- 服务器收到请求后,比对提交的Token和会话中存储的Token是否一致。只有一致,才处理请求。
为什么Token能防御CSRF?因为攻击者无法提前知道或获取到受害者当前会话中的有效Token。他们构造的恶意请求中要么没有Token,要么是一个无效的Token,服务器会因此拒绝请求。
在DVWA中观察防御演进:
- Medium等级:DVWA尝试检查
Referer头是否包含自己的主机名。但可以通过一些方式绕过(例如,如果网站同时存在XSS漏洞,攻击者可以从站内发起请求,Referer就是合法的)。 - High等级:DVWA引入了CSRF Token。查看页面源码,你会发现表单里多了一个隐藏的
user_token字段,每次页面刷新这个值都会变化。任何没有携带正确Token的请求都会被拒绝。
3. 使用自定义请求头对于通过AJAX发起的API请求,可以要求客户端在请求头中携带一个自定义字段(如X-Requested-With: XMLHttpRequest)。因为浏览器在发起跨域请求时,默认不允许前端代码添加自定义头(遵循CORS规则),所以由恶意页面发起的CSRF请求无法包含这个头。但这种方法依赖于前端代码的配合,且对于非AJAX的传统表单提交无效。
4. SameSite Cookie属性这是一个浏览器端的防护机制。在设置Cookie时,可以指定SameSite属性为Strict或Lax。
SameSite=Strict:浏览器只会在同站请求(即当前页面URL的站点与请求目标站点一致)中发送此Cookie。这能完全阻止CSRF,但可能导致用户体验问题(例如从邮件链接点击进入网站,登录态会丢失)。SameSite=Lax(默认值):在安全的上层请求(如GET请求)中发送Cookie,但对于POST等非安全方法则不发送。这能在安全性和可用性之间取得平衡,防范大多数POST型CSRF攻击。
实操心得:在实际开发中,CSRF Token是必须的。对于重要的操作(登录、改密、支付、数据变更),务必使用POST请求+CSRF Token。框架(如Spring Security, Django, Laravel)通常内置了CSRF防护中间件,开箱即用,但你需要理解其原理并确保在前端正确携带Token(例如,在AJAX请求中,需要从meta标签或Cookie中读取Token并添加到请求头或参数中)。同时,将关键的会话Cookie设置为
SameSite=Lax或Strict,可以增加一道额外的防线。
5. 从漏洞利用到代码审计:构建主动防御思维
经过前面的实战,我们已经能够成功利用并防御基础的XSS和CSRF漏洞。但作为一名开发者,我们的目标不应只是会“攻防”,更要建立起一套主动发现和修复安全问题的思维模式。这就是代码审计和SDL(安全开发生命周期)的雏形。
5.1 针对XSS的代码审计要点
当你审查一段代码时,如何快速判断是否存在XSS风险?关注以下几个模式:
- 寻找“回声”函数:在PHP中,如
echo,print,printf,<?= $var ?>;在Java中,如out.print();在Python Flask/Jinja2中,如{{ variable }}(未转义时);在JavaScript中,如innerHTML,document.write()。这些是将数据输出到页面的关键点。 - 追溯变量来源:检查输出到上述“回声”点的变量,它的值从哪里来?如果是来自
$_GET,$_POST,$_REQUEST,$_COOKIE,或者从数据库、API接口获取的用户先前输入的数据,那么它就是“用户可控的输入”。 - 检查过滤与编码:在变量被“回声”之前,是否经过了适当的过滤或编码?对于HTML上下文,是否使用了
htmlspecialchars($var, ENT_QUOTES, 'UTF-8')(PHP)或类似的函数?注意,ENT_QUOTES标志很重要,它能同时转义单引号和双引号。对于JavaScript或URL上下文,是否有对应的编码函数? - 警惕拼接字符串:任何使用字符串拼接(如
"Hello, " + username + "!")或模板字符串(如`Hello, ${username}!`)来动态生成HTML或SQL语句的地方,都是高危区。必须确保变量在拼接前已正确编码。
一个简单的审计清单:
- [ ] 所有渲染到HTML页面的动态数据,是否都经过HTML实体编码?
- [ ] 所有作为JavaScript变量值输出的数据,是否经过JavaScript编码(如使用
JSON.stringify)? - [ ] 所有放入HTML属性(如
href,src,onclick)的数据,是否经过HTML属性编码(htmlspecialchars默认处理)? - [ ] 是否避免了不安全的JavaScript函数,如
eval(),setTimeout(string),new Function(string)?
5.2 针对CSRF的代码审计要点
审计CSRF防御,主要看服务器端对状态变更请求的处理。
- 识别状态变更操作:哪些请求会修改数据(增删改)或状态(登录、注销、支付)?这些通常是POST、PUT、DELETE请求,有时也包括GET(不推荐)。
- 检查CSRF Token:
- 对于每一个状态变更的端点(Endpoint),是否要求验证CSRF Token?
- Token的生成是否足够随机(使用密码学安全的随机数生成器)?
- Token是否与用户会话绑定?是否一次性使用或有时效性?
- 前端表单或AJAX请求是否正确携带了Token?(检查隐藏字段或请求头如
X-CSRF-TOKEN)
- 检查关键Cookie的SameSite属性:会话Cookie(如
PHPSESSID,JSESSIONID)是否设置了SameSite=Lax或Strict? - 检查Referer/Origin验证:虽然不能作为唯一依赖,但可以作为辅助手段。检查代码中是否对敏感操作验证了请求来源。
一个简单的审计清单:
- [ ] 所有非幂等的操作(POST/PUT/DELETE)是否都配备了CSRF Token验证逻辑?
- [ ] Token是否随机、与会话关联、并有效防重放?
- [ ] 会话Cookie是否设置了安全的
SameSite属性? - [ ] 对于重要的API,是否考虑验证
Origin头?(尤其用于防范跨域AJAX的CSRF)
5.3 将安全融入开发流程:SDL初探
安全不应该只是测试阶段或上线前的一次性工作。SDL倡导将安全活动集成到软件开发的每一个阶段。
- 需求与设计阶段:进行威胁建模。思考你的应用有哪些资产(用户数据、支付接口、管理后台),可能面临哪些威胁(XSS导致数据窃取、CSRF导致未经授权操作),并据此设计安全控制措施(如输入验证架构、认证授权模型)。
- 编码阶段:使用安全的编码规范和函数库。例如,强制使用参数化查询或ORM来防SQL注入;使用自动转义输出的模板引擎;启用框架内置的CSRF保护。进行结对编程或代码审查时,将安全作为一项必查项。
- 测试阶段:除了功能测试,必须进行安全测试。包括:
- 自动化扫描:使用工具(如OWASP ZAP, Burp Suite Scanner)对应用进行漏洞扫描。
- 手动渗透测试:像我们之前做的那样,模拟攻击者进行测试。
- 代码审计:定期或针对核心模块进行源代码安全审查。
- 部署与运维阶段:确保服务器、中间件、数据库的配置安全(如关闭不必要的服务、更新补丁)。配置安全响应头(如CSP, HSTS, X-Frame-Options)。建立监控和日志审计机制,以便在发生安全事件时能快速响应和追溯。
6. 常见问题与排查技巧实录
在实际操作和开发中,你肯定会遇到各种各样的问题。下面是我总结的一些典型场景和解决思路。
6.1 XSS相关疑难杂症
问题1:明明输入了``,页面也显示了,但为什么不弹窗?
- 可能原因1:内容被HTML编码了。右键查看页面源代码,看看你的输入是不是被转换成了
<script>alert(1)</script>。如果是,说明服务器端做了正确的输出编码,漏洞不存在。 - 可能原因2:脚本被浏览器内置的XSS过滤器拦截了。现代浏览器(如Chrome、Edge)都有内置的反射型XSS过滤器。可以尝试更复杂的payload或使用其他浏览器测试。但这不代表应用是安全的,因为过滤器并非百分百可靠。
- 可能原因3:脚本注入到了错误的上下文。例如,你的输入被放到了HTML标签的属性里,如
。此时,你需要闭合前面的属性,然后引入事件处理器,如`" onmouseover="alert(1)`,最终形成。
问题2:在真实项目中,如何测试富文本编辑器(如CKEditor、TinyMCE)的XSS防护?富文本编辑器允许用户输入HTML,这带来了巨大的XSS风险。测试时:
- 测试黑白名单过滤:尝试输入一些危险的标签和属性,如
,,看是否被过滤或转义。 - 测试绕过:尝试使用大小写混合、嵌套标签、无效属性、Unicode编码、HTML实体编码等方式,看能否绕过过滤规则。例如,输入``。
- 关注
><meta name="csrf-token" content="{{ csrf_token() }}">// 使用Fetch API fetch('/api/endpoint', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content') }, body: JSON.stringify(data) }); - 方法B:服务器将Token设置在Cookie中(需确保Cookie的
HttpOnly为false,以便JS读取),前端JavaScript从Cookie中读取并添加到请求头或参数中。但这种方法要注意防范XSS窃取Token。 - 登录后获取:用户登录成功后,后端在响应中返回一个CSRF Token(可以放在JSON响应体或一个非
HttpOnly的Cookie中)。 - 前端存储:前端将这个Token存储在内存(如Vuex/Redux)或Web Storage(
sessionStorage)中。不建议放在localStorage,因为它对XSS攻击没有抵抗力。 - 请求时携带:在发起任何非GET请求时,将Token添加到请求头(如
X-CSRF-TOKEN)。 - Token刷新:可以考虑为Token设置较短的有效期,或在每次使用后刷新,以降低被窃取后的影响窗口。
- 解决方案:对于需要处理第三方回调的端点(如
/auth/callback,/payment/notify),可以单独处理。要么不使用依赖该会话Cookie的认证方式(例如使用一次性token),要么将该端点的Cookie策略调整为SameSite=None; Secure(注意,None必须与Secure一起使用,即要求HTTPS)。 - 在浏览器中访问虚拟机时,使用虚拟机的局域网IP地址(如
192.168.1.xxx),而不是localhost或127.0.0.1。 - 在Burp Suite的Proxy -> Options -> Proxy Listeners中,确保监听的是所有接口(
0.0.0.0:8080)或特定IP。 - 在浏览器或系统设置中,为HTTP/HTTPS代理明确指定Burp Suite的IP和端口。
- 检查
/var/www/html/DVWA/config/config.inc.php文件中的数据库连接信息(主机、用户名、密码、数据库名)是否正确。 - 检查MySQL服务是否正在运行:
sudo systemctl status mysql。 - 尝试重新运行
setup.php页面重置数据库。 - 查看Apache错误日志获取详细信息:
sudo tail -f /var/log/apache2/error.log。
问题2:单页应用(SPA)如何管理CSRF Token?SPA与后端API交互频繁,Token管理是关键。
问题3:SameSiteCookie属性设置后,第三方登录/支付回调失败了怎么办?这是因为第三方网站在回调你的站点时,属于跨站请求。如果会话Cookie设置了SameSite=Strict,浏览器不会发送这个Cookie,导致你的后端无法识别用户会话。
6.3 工具使用与调试技巧
Burp Suite抓不到本地虚拟机(localhost)的包?这是因为浏览器对localhost有特殊处理。解决方法:
DVWA页面显示“数据库连接错误”或空白页?
最后,我想分享的一点个人体会是,Web安全的学习没有终点。XSS和CSRF只是OWASP Top 10中的两个经典代表。当你熟练掌握了它们,可以继续挑战SQL注入、文件上传漏洞、SSRF、反序列化等等。但无论漏洞如何变化,其核心思想是相通的:不信任任何用户输入,在正确的上下文进行编码输出,对关键操作实施二次确认和防伪造机制。养成这些安全编码习惯,比你临时抱佛脚学习各种漏洞利用技巧要重要得多。最好的防御,是让漏洞在你的代码中无处可生。