经常有打算入门网络安全或者刚转岗到安全方向的朋友私信问我,DVWA该怎么练。大多数人手里拿着一份通关教程,跟着点来点去,结果连页面都刷不出来,或者好不容易进了模块,却发现别人的操作在自己这里完全不好使。借这篇,我把自己的完整通关思路写一遍,包含环境搭建、安全等级机制、各个漏洞模块的实操逻辑,以及那些教程里基本不会写的坑。
DVWA是一套开源的Web安全漏洞测试靶场,全称叫Damn Vulnerable Web Application。它把SQL注入、跨站脚本(XSS)、CSRF、文件上传、命令注入这些入门必碰的Web漏洞做成了一个个独立模块,还内置了四档难易等级。它解决的最大痛点是:新手不需要自己手写漏洞代码,不用搭复杂的业务系统,本地起一个环境,浏览器里就能合法地练手。这篇文章适合刚接触网络安全的零基础读者,也适合那些刷过几篇通关帖但始终没搞懂漏洞原理的人。如果你已经能独立完成DVWA所有模块,建议直接跳到最后一节看进阶路线。
1. 为什么新手的第一个靶场,我推荐DVWA
1.1 靶场选型:DVWA到底解决什么问题
市面上能拿来练手的靶场其实不少,有的集成了几十个漏洞,有的侧重渗透测试全流程,还有的基本就是一套带漏洞的完整业务系统。但问题也很明显,很多复杂靶场对新手来说光部署就要折腾一整天,装完以后根本不知道下一步该干什么,观赏价值远大于练习价值。
DVWA恰恰相反。它把每个漏洞做成了独立菜单,左边点进去就是一个极致简化的漏洞页面。以SQL注入模块为例,页面上只有一个输入框和一张查询结果表,所有干扰项全部被去掉,你能专注感受注入逻辑本身。这种设计思路符合学习规律:一开始不能把复杂度拉满,要让新手清楚看到输入、处理、输出三个环节之间发生了什么。
另外一个重要优势是,DVWA自带四种安全等级。同一个漏洞,你能在Low等级下看到完全没有防护的写法,在Medium等级看到有过滤但可以绕过的写法,在High等级看到更严格但仍然“不够安全”的写法,最后在Impossible等级看到防御到位、代码无懈可击的正确姿势。这种纵向对比,是其他很多靶场给不了的学习体验。
1.2 本地环境部署:两种方式快速跑起来
部署DVWA主要有两种方案,我个人优先推荐Docker方式,隔离性最好,删了重建也不心疼。
Docker方式的完整步骤如下:
# 拉取DVWA镜像 docker pull vulnerables/web-dvwa # 启动容器,把容器的80端口映射到本机的8080端口 docker run -d -p 8080:80 --name dvwa vulnerables/web-dvwa # 确认容器已经正常运行 docker ps启动后用浏览器访问 http://localhost:8080,默认用户名是admin,密码是password。首次登录会看到一个提示页,点击页面下方的“Create / Reset Database”按钮初始化数据库,之后会自动跳到登录页,重新用admin/password登录就能进入主界面。
如果你不想用Docker,传统方式也可以:本机装一套PHP集成环境(Apache + MySQL + PHP的整合包),把DVWA源码放进网站根目录,手动创建数据库并导入配置,同时修改配置文件里的数据库账号密码。这里有一个非常容易踩的坑:配置文件里的默认密码不一定和本地数据库实际密码一致,导致页面能打开,但所有模块都报数据库连接错误。
无论用哪种方式,都请牢牢记住一个原则:DVWA这种漏洞环境只允许在本机或自己控制的测试环境里运行,不要把它暴露到公网,不要在上面放任何真实业务数据。这个底线决定你后续做的事是安全学习还是别的。
1.3 学会看DVWA源码目录,这步很多人跳过
部署完成之后,别急着开始刷漏洞,先看一眼DVWA的源码目录。如果你用的是Docker方式,可以通过以下命令进入容器查看:
docker exec -it dvwa bash源码一般位于 /var/www/html/ 目录。里面每个漏洞模块都有对应的PHP文件,文件名和菜单一一对应,比如 SQL Injection 对应 sqli.php,文件上传对应 upload.php。每个模块的源码其实不长,几十行而已,但信息量极大。
我强烈建议你在每个漏洞模块通关前,先打开对应的源码文件读一遍。大多数时候你不需要看太懂,只需要找到核心处理逻辑,比如接收参数后是否直接拼进SQL语句、输入输出之间有没有做处理。这个习惯能让你从“照着工具点来点去”进化成“看着代码理解漏洞”,是性价比最高的学习方法。
2. 先搞懂安全等级:通关路线的总开关
2.1 四档难度背后的设计逻辑
DVWA左侧菜单中有个“DVWA Security”页面,能切换安全等级。很多新手完全忽略了这个设置,上来就直接刷,然后发现有的模块能成功,有的模块怎么试都不行,根本原因是安全等级没有统一。
四个等级本质上是四种开发水平的模拟:
| 等级 | 类型 | 类比 |
|---|---|---|
| Low | 无任何防护 | 家里门不锁,推门就进 |
| Medium | 简单过滤,可绕过 | 门上了普通挂锁,撬一下就开 |
| High | 多层校验,仍有缺陷 | 门装了防盗锁,但窗户没关 |
| Impossible | 安全写法 | 保险柜加监控,正面突破很难 |
这个设计非常高明。Low等级把漏洞最原始的成因暴露出来,Medium和High则在漏洞外面加了一层又一层的过滤,让你体会开发者“试图修复但修不彻底”的状态,而Impossible则是标准答案。
通关的第一个核心思路是:先把所有模块在Low等级下刷一遍,然后再逐个模块挑战Medium、High,最后看Impossible的源码,理解安全写法长什么样。不要一开始就挑战高级等级,否则连漏洞怎么触发都不知道,绕过滤更是无从谈起。
2.2 切换安全等级后必须做的一件事
切换安全等级的位置在DVWA Security页面,下拉框选择等级后点Submit。但很多人不知道:切换等级之后,最好立刻去Setup页面重新执行一次“Create / Reset Database”。
为什么必须重置数据库?因为前面你在Low等级做实验时,已经在数据库里写入过数据。比如存储型XSS模块,你往留言板里写入了恶意脚本,又比如SQL注入模块的暴力尝试改写了表结构。这些残留数据会干扰你在Medium或High等级下的判断,很可能你想验证的输出根本不出来。
具体做法:进入Setup页面,拉到最下面,点击“Create / Reset Database”按钮,等待提示成功后,再回到DVWA Security页面确认当前等级,之后进入目标模块。
这里我踩过不止一次:有个项目里我一直在High等级测SQL注入,但页面上始终显示我在Low等级时插入的那条数据,导致我以为自己绕不过去,折腾了很久才发现只是数据库没有重置。这个环节虽然不起眼,却是通关过程中最容易让人心态崩溃的隐性问题。
2.3 推荐的通关顺序
不同模块的难度不一样,通关顺序建议如下:
- 先做暴力破解(Brute Force),模块逻辑最简单,核心是理解HTTP请求和响应
- 再做命令注入(Command Injection),让你感受代码到底执行了什么
- 接着是SQL注入(SQL Injection),这是Web安全里最核心的知识点
- 然后做XSS相关模块,包括反射型和存储型
- 再做CSRF和文件上传,这两个一个考验业务逻辑理解,一个考验对服务端校验的认知
- 最后做JavaScript和弱会话ID这类偏冷门模块
按照这个顺序的好处是,每个模块都能复用上一个模块建立起来的思路。比如你在SQL注入里学会了“闭合前文、注释后文”的思路,在XSS里同样用得上;在暴力破解里理解了Cookie和会话机制,再去看CSRF会轻松很多。
3. 数据分析型漏洞:SQL注入与跨站脚本
3.1 SQL注入模块:从报错到Union查询
SQL注入是整个DVWA里最值得反复练的模块,没有之一。它彻底改变你对“输入”这件事的理解。
Low等级下,页面上只有一个ID输入框。输入数字1,页面正常显示ID为1的用户信息,这时的SQL大致是:SELECT first_name, last_name FROM users WHERE user_id = '1'。输入一个单引号,页面直接报错,说明你的输入被拼进了SQL语句,破坏了语法结构。这就是注入点存在的证据。
接下来说说联合查询的思路。你先试着用 ORDER BY 语句判断查询结果有几列。输入 1' ORDER BY 2 -- 正常显示,改成 1' ORDER BY 3 -- 报错,说明这条查询只有2列。确定了列数之后,就可以用 UNION SELECT 让后面的查询结果和原有查询合并返回。比如在回显位置替换成数据库函数,能够直接看到当前数据库名。
到这里你其实已经能完成Low等级通关了。Medium等级的源码对单引号做了转义处理,大部分带引号的注入会直接失败,但注入点前面的参数本身是数字类型,你完全可以用 1 OR 1=1 这样不含引号的语句测试恒真条件,页面会返回所有记录。到High等级,代码在SQL语句末尾加了一个LIMIT 1,把返回行数限制为1,此时你依然可以让UNION查询只返回一行数据,配合尾部注释闭合掉限制条件。
这个模块通关最重要的收获不是记住payload,而是理解预编译和参数化查询。看Impossible等级源码你会发现,参数和SQL语句被完全分离,用户输入只会被当作数据去处理,永远不可能变成SQL代码的一部分。这也是为什么现在企业级开发都会强制使用ORM和预编译语句。
3.2 XSS模块:输入输出不分离的教训
XSS模块分为反射型和存储型两种,页面里能直接看到对应菜单。它的本质问题不是“标签过滤不够多”,而是“用户输入被当成了页面代码的一部分执行”。
Low等级的反射型XSS最简单,在输入框提交 ,页面直接弹窗。你输入的内容原样出现在HTML里,浏览器把它当作代码执行了。存储型则是把这段内容写进了数据库,等下一个用户访问页面时自动触发,效果更持久、危害更大。
Medium等级用了搜索替换的方式把“script”替换成空字符串。很多新手以为这就安全了,但实际上替换只做了一次,你输入 <scr ,中间的script被删掉后剩下的恰好拼回一个完整的script标签。这种双写绕过的思路,本质上是因为“过滤”和“语义解析”发生的时间点不同。
High等级把更多危险标签和事件属性列入了黑名单,直接过滤script、iframe以及onclick这类关键词。但黑名单的思路天然有局限,总会有没考虑到的标签和属性组合。Impossible等级的做法是在输出端进行实体编码,让尖括号变成无害的<和>,这样无论你输入什么,浏览器都只会当成文本展示。
我的建议是,XSS通关时不要只记绕过姿势,要学会动态看页面源码结构,观察你的输入究竟渲染在哪个HTML上下文里。上下文不同,防护方式也完全不同,这个认知能让你后续看代码审计时有质的提升。
4. 逻辑与系统层漏洞:CSRF、文件上传与命令注入
4.1 CSRF模块:修改密码的“钓鱼”实验
CSRF模块在DVWA里做的是修改密码功能。攻击思路是:你已经在靶场登录了,浏览器自动携带会话Cookie,攻击者构造一个指向密码修改接口的请求,诱导你点击,密码就在你不知情的情况下被改掉了。
Low等级的改动密码表单里没有任何随机Token,请求里只有新密码和确认密码。你完全可以用一个本地HTML页面模拟这个请求,里面放一个自动提交的表单,action指向DVWA的修改密码URL,参数填好,打开页面就触发修改。这里仅限在本地靶场做实验,需要说明的是,真实场景中攻击者会把这个页面藏到各种诱导链接里,危害很大。
Medium等级在服务端加了Referer校验,只接受来自本站的请求。外部构造的请求会因为没有正确的Referer头而被拒绝。听到这里你应该能感觉到,只要开发者信任了Referer,就会产生新的绕过思路。到了High等级,服务端引入了随机Token,每个用户会话都有独立的Token值,修改密码时必须提交这个Token。外部页面拿不到Token,CSRF攻击自然就失败了。
通关这个模块时,有个容易被忽略的点:DVWA的CSRF实验修改的是 admin 用户的密码,改完以后你当前登录状态并不会退出,但下次登录就得用新密码。所以很多人测完CSRF,第二天再登录发现密码错误,还以为靶场坏了。
Impossible等级的做法是强校验:要求用户输入当前密码才能设置新密码,同时配合Token校验。这个思路在真实系统里也是标准姿势,任何敏感操作都必须二次验证当前用户身份。
4.2 文件上传模块:黑白名单与MIME校验
文件上传是一个实际工程项目里高频出现的安全风险点,DVWA里专门设计了从Low到High的由简到复杂过程。
Low等级的上传模块基本没有任何限制,你直接上传一个PHP测试脚本,比如内容为 的文件,访问上传目录后就能看到PHP信息输出。说明服务器把这个文件当作PHP代码执行了。这里需要提醒的是,上传目录一般就在当前页面同级的 ../hackable/uploads/ 路径下,通关时可以通过查看页面源码找到具体路径。
Medium等级开始检查文件类型,但只是根据HTTP请求里的Content-Type字段来判断,比如要求Content-Type必须等于image/jpeg。解决方法是上传前用抓包工具把Content-Type改成image/jpeg,文件内容仍然是PHP脚本,服务器执行的是内容而不是请求头,于是校验形同虚设。
High等级聪明了一点,同时检查文件扩展名和文件头。扩展名必须是图片格式,文件内容头部也要是图片的魔数。这时候直接传PHP脚本已经行不通了,一个常见思路是先上传一个合法图片,把PHP代码塞进图片的注释区,再结合文件包含漏洞去触发执行。这也就是常说的图片马,但在DVWA里,你需要配合文件包含模块一起使用,单独玩文件上传模块体会不到这个组合链路。
Impossible等级采用了白名单扩展名、随机文件名、限制文件大小并结合内容检测,基本锁死了大部分绕过路径。这也是真实文件存储系统的标准防御思路。整个模块练下来,你最大的收获应该是:永远不要相信用户传上来的文件名和类型,必须依靠服务端的多重校验。
4.3 命令注入与暴力破解:常见的两个入门坑
命令注入模块做的是一个Ping功能,页面会让你输入一个IP地址,后端把输入直接拼接到系统命令中。Low等级输入 127.0.0.1 会正常回显ping结果,但你如果输入 127.0.0.1 | whoami,命令拼接后相当于执行了“先ping,再查看当前用户”,页面会把两条命令的结果一起显示出来。这个竖线符号在Linux里的意思就是“把前一条命令的输出作为后一条的输入”,熟悉命令行的读者会觉得很自然。
Medium等级过滤了 && 和 ; 这类常见拼接符号,但竖线仍然可以用,又或者可以用换行符拆分命令。High等级增加了更严格的黑名单过滤,但黑名单的思路还是很难覆盖所有拼接方式。Impossible等级不再使用系统命令拼接,而是直接对IP做了严格校验,只用PHP的内置函数去判断输入,从根本上杜绝了命令注入。
暴力破解模块则不同,它纯粹考验你对认证流程的理解。Low等级登录页没有任何防护,抓包工具连续发送不同密码的请求就能逐项尝试。Medium等级增加了2秒延迟,爆破速度明显变慢。High等级引入了随机Token,每次请求前得先从前一个响应里提取新的Token再提交,批量爆破脚本就没那么简单了。Impossible等级直接实现了登录失败次数限制和账号锁定机制。
玩暴力破解时,很多新手犯的错误是拿着大字典硬跑Medium和High等级的靶场,跑到怀疑人生。正确做法是先抓包看请求结构,再去理解服务端是怎么校验的,而不是无脑循环。这个思维方式,后面一直到真实环境测试都管用。
5. 通关路上最常见的坑和排查办法
5.1 高频报错与原因对照表
有了上面这些通关经验,我整理一份高频问题对照表,基本覆盖了90%的翻车场景:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 页面打不开 | Docker端口被占用 | 换宿主端口重新映射 |
| 页面能开但报数据库错误 | 数据库未初始化或密码不匹配 | 去Setup页重置数据库 |
| 安全等级切换后模块无变化 | 数据库残留数据 | 重新Create / Reset Database |
| SQL注入语句无效果 | 当前等级不是Low | 确认等级并对比源码 |
| 上传文件访问404 | 上传路径不对或文件名被改写 | 看页面源码找到真实上传路径 |
| XSS弹窗不出现 | 输出被转义或过滤 | 检查输入点和输出点的位置关系 |
| 命令注入没有输出 | PHP禁用相关函数 | 检查php.ini的disable_functions |
| CSRF改密码无效 | 请求头存在Referer或Token校验 | 先满足服务端校验条件 |
每次遇到问题,先不要急着怀疑教程有问题,按照“页面层 -> 请求层 -> 源码层”的顺序一层层排查。页面层看是否报错,请求层用抓包工具看参数是否完整,源码层直接读对应PHP文件确认校验逻辑。绝大多数问题都能在这个链条上定位。
5.2 三类最隐蔽的翻车现场
第一类:脚本失灵是因为等级变了。你在Low下用的payload,切到Medium大概率失效,这是因为服务端新增了过滤。很多新手反复刷新页面,却不记得切等级,浪费大量时间。建议每次切换模块前,先看一眼DVWA Security页面。
第二类:数据库脏数据干扰判断。尤其是存储型XSS和SQL注入模块,前面等级留下了大量历史数据。我之前就遇到过一个问题:在High等级下明明已经没有注入点了,但页面还显示着之前注入产生的数据,差点误判。重置数据库之后一切恢复如初。
第三类:混淆了容器内和真实系统的差异。DVWA容器里运行权限比较高,命令注入执行whoami返回root,不代表真实系统也是这个权限。很多人练完靶场之后心态膨胀,跑到真实系统里做类似操作,这是极其危险的行为。只要记住“靶场就是靶场,真实系统必须在授权前提下才能碰”这条线,后面怎么学都不会偏。
6. 从靶场通关到真实项目,还要多走这几步
6.1 靶场和真实系统之间,隔着“授权”和“业务逻辑”
DVWA可能给你一个错觉,漏洞看起来都挺简单,SQL注入就那么几个payload,XSS就是弹个窗,文件上传就是传个好看的脚本。但真实系统远没有这么单纯,业务逻辑复杂、权限关系重叠、多层服务交互,再加上各种风控和防护设备,漏洞的利用链路往往长得多。
这恰恰说明了靶场的定位:它训练的是一种识别问题的“手感”,让你知道漏洞长什么样、触发条件是什么、防御姿势有哪些。从靶场到真实系统,中间必须补三门课:第一门是HTTP协议细节和浏览器工作机制,第二门是常见框架和数据库的底层原理,第三门是代码审计能力,也就是直接通过读源码找问题。这三门课都需要你自己在本地搭业务系统去练,不要拿着测试工具去扫没有授权的网站。
6.2 一条更踏实的学习路径
我个人建议的路线是这样的:先把DVWA所有模块在Low等级下通关,做到不看任何教程也能复现利用过程;然后逐个切到Medium和High,尝试自己在纸上写出绕过思路;接着重点读Impossible源码,分析为什么这种写法能防住注入和XSS;最后,自己搭一个带登录、留言、文件上传的简单业务系统,尝试用DVWA里学到的思路给这个系统做一轮安全自查。
等你觉得这些已经不够练手了,可以尝试复现一些真实的漏洞案例,在本地环境搭建对应版本的中间件或者开源应用,围绕具体的漏洞编号分析成因和修复方案。再往后就是往代码审计方向深入,读开源项目的源码,把“读代码找问题”变成肌肉记忆。这个过程没有捷径,但比盲目刷几十个靶场有效得多。
我自己早期刷DVWA时也是跟着别人的教程一步步走,以为过关就是学会,后来再回头看,真正让自己进步的节点,反而是那些卡了很久、反复读源码、终于悟透某一个过滤为什么可以被绕过的时候。现在拿起DVWA从头再过一遍,你会发现自己看到的东西完全不一样了,这就是这门课真正开始起作用的时候。