这门课排出来的时候,实验手册上就一句话:"完成 Web 应用安全基础实验,内容包括环境搭建、协议分析与会话劫持。"我当时以为很简单,结果前前后后折腾了两个星期。做完之后回头想,这其实是整个 Web 安全课程里含金量最高的一课——它把网络协议、HTTP 机制、身份认证和安全攻击串成了一条完整的线。
先说这个实验适合谁:如果你正在学 Web 安全、在做网络协议分析的课程设计,或者准备打 CTF 但看不大懂抓包数据,这篇内容踩过的坑和完整步骤可以直接照着操作。整套环境都是本地虚拟机搭建,不涉及任何真实业务系统,你在一台普通电脑上就能完整体验。我会按实验本身的顺序来讲:先想清楚要做什么和为什么,再把环境搭起来,然后用 Wireshark 和 Burp 把 HTTP 协议分析透,最后用 Cookie 把一场会话劫持从头到尾演一遍。
1. 实验目标与思路拆解
1.1 这个实验究竟在考察什么
实验名字里三个关键词,每一个都不是装饰。环境搭建考察的是你能否在可控条件下构造一个"靶场";协议分析考察的是你能不能看懂网络上真实流动的数据;会话劫持则是前两项的交叉考核——你要理解 Session 的生成、传递和验证机制,才能解释为什么一个简单的 Cookie 能变成攻击者的入场券。
我身边不少同学第一反应是直接去搜"会话劫持 exp",想在真实站点上试一下,这其实走错了方向。这个实验的重点不在"打进去",而在"看懂过程"。你只有先把 HTTP 无状态、Cookie 携带、Session 服务端存储这三个概念吃透,劫持实验才不是机械地抄别人步骤。课程在做前置铺垫时,前面还有 IP 协议分析、DNS 协议分析这类实验,它们解决的是"数据包怎么走"的问题,而 Web 安全实验要解决的是"应用层怎么识别一个人"的问题,两者正好衔接。
更直白地说,这个实验考的是三层递进关系。第一层是你会不会搭环境,这是动手能力。第二层是你能不能用抓包工具把一次 HTTP 请求拆成裸数据来分析,这是观察能力。第三层是你能不能利用协议设计中被忽略的信任假设去复现攻击,这是安全的思维模式——站在攻击者角度想问题。
1.2 为什么是这三项技术的组合
如果你只学协议分析,不碰安全,你会觉得 Cookie 只是个普通字段。如果你只学攻击,不学协议,你会不知道为什么改了 Cookie 就能伪装身份。这个实验的精妙之处,就是把两者强行绑定在一起。
举个例子,TCP 三次握手建立连接、HTTP 请求在连接上发送、服务器通过响应头里的 Set-Cookie 下发 Session ID、浏览器后续请求通过 Cookie 头把 Session ID 送回——这一整条链路里,Web 安全的攻防点到处都是。会话劫持的核心,是服务器只凭 Cookie 里的 Session ID 来判断"你是谁",而这个 ID 在网络上是可被截获、可被伪造、可被重放的。如果不先把协议链路看明白,你压根不知道攻击要落在哪个环节。
后面我会反复提到一个观点:安全实验的本质是验证协议的信任假设。HTTP 信任了 Cookie 里的一个随机字符串,会话劫持就是对这个信任的滥用。我们从协议分析和攻击复现两个方向逼近同一个问题,互为印证。
1.3 环境选型为什么这么定
这个实验我推荐三个角色:一台靶机虚拟机、一台装有抓包和篡改工具的"攻击机"、一条能隔离的网络。具体选型上,我用了 VirtualBox + Ubuntu 20.04 做靶机,物理机 Windows 装工具做攻击端,网络模式选择"仅主机(Host-Only)"。
为什么不选自己手写一个带登录功能的站点?因为 DVWA 这类现成靶场自带多种安全级别,可以在一套代码里对比"低安全级别"和"高安全级别"下 Cookie 行为的不同,比自己写省事且更贴近真实场景。为什么不用桥接网络直接挂到局域网里?因为实验里的攻击手法如果跑在真实局域网里,很容易误伤其他设备,而且 IP 分配不可控。仅主机网络相当于在虚拟机和物理机之间拉了一条私有网线,隔离效果好,IP 还能固定下来。
至于工具,抓包用 Wireshark,数据包修改和重放用 Burp Suite。这两个都是安全从业者的日常工具,免费版就够用,后面我会标注清楚每一步用的是哪个模块。
2. 环境搭建:一台靶机、一套工具链
2.1 网络模式与 IP 规划
先说网络,这是第一个大坑。很多人在实验里用的是 NAT 模式,虚拟机虽然能上网,但物理机访问不到虚拟机的 Web 服务,浏览器里怎么敲 IP 都是拒绝连接。原因很简单:NAT 模式下虚拟机对外是"隐藏"的,数据出去要经过宿主机的地址转换,外部主动发起的请求进不来。
正确做法是在 VirtualBox 里给靶机添加第二块网卡,选"仅主机网络"。装完系统后,我在 Ubuntu 里把网卡配置成静态 IP:10.10.10.10,子网掩码 255.255.255.0。物理机同样在这个网段,比如10.10.10.1。两边互相 ping 得通,实验网络就通了。
# Ubuntu 22.04 用 netplan 配置静态 IP sudo nano /etc/netplan/01-network-manager-all.yaml # 写入以下配置 network: version: 2 ethernets: enp0s8: dhcp4: no addresses: [10.10.10.10/24] sudo netplan apply注意:仅主机网络的默认网段经常是 192.168.56.x,这没问题。我这里特意选 10.10.10.x 是为了避免和家里路由器网段冲突,实际以你的 VirtualBox 全局设置里看到的网卡信息为准。
IP 规划这事其实很值得多想一步。固定靶机 IP 不仅是为了方便浏览器访问,更重要的是后面的协议分析实验里,Wireshark 过滤条件可以直接写ip.addr == 10.10.10.10,一眼就能把靶机相关流量筛出来,数据包干净很多。
2.2 DVWA 靶场部署步骤
DVWA(Damn Vulnerable Web Application)是我最喜欢的 Web 安全入门靶场,没有之一。它的部署依赖 LAMP 环境,也就是 Linux、Apache、MySQL、PHP。先装基础组件,再把 DVWA 源码放到 Web 目录下。
整个过程用下面的命令就能走通,我在安装过程中碰到的两个典型问题会单独标注。
# 更新并安装 LAMP 环境 sudo apt update sudo apt install -y apache2 mysql-server php php-mysqli libapache2-mod-php git # 拉取 DVWA 源码并放到网站根目录 cd /var/www/html sudo git clone https://github.com/digininja/DVWA.git sudo mv DVWA dvwa # 准备 DVWA 配置文件 cd /var/www/html/dvwa/config sudo cp config.inc.php.dist config.inc.php # 创建测试文件验证 PHP 是否正常 echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/test.php这里有个很多人必踩的坑:DVWA 的 config.inc.php 里数据库密码默认是空字符串,但 MySQL 8 默认 root 用的是 auth_socket 认证,PHP 连数据库时会报 Access denied。我当时卡了很久,最后是在 MySQL 里创建了一个专用账号给 DVWA 用,再把 config 里的密码改成这个账号的密码。
CREATE USER 'dvwa'@'localhost' IDENTIFIED BY 'dvwa_pass'; GRANT ALL PRIVILEGES ON dvwa.* TO 'dvwa'@'localhost'; FLUSH PRIVILEGES;完成之后,访问http://10.10.10.10/dvwa/setup.php,点页面下方的Create / Reset Database按钮,DVWA 会自动建库并初始化数据。看到绿色提示就说明环境通了。整个实验完全本地化,不依赖任何在线的免费 Web 服务器,网络断了也不影响。
2.3 工具链装配与关键验证
靶机就绪后,物理机上要装三样东西:Wireshark、Burp Suite Community 免费版、Firefox 浏览器及 Cookie-Editor 插件。Wireshark 抓包需要管理员权限,安装时务必把 WinPcap 或 Npcap 核心组件勾选上,否则抓不到任何数据包。
Burp Suite 打开后默认会监听本机 8080 端口,我需要在浏览器里把流量转到它的监听端口上。这一步很多人容易漏掉,不设置的话 Burp 只会空转,什么都拦截不到。Firefox 在"连接设置"里选择手动配置,HTTP 和 HTTPS 都填127.0.0.1:8080。
工具装完先做个验证:打开 Wireshark 选择仅主机网卡开始抓包,然后用浏览器访问http://10.10.10.10/dvwa/login.php。如果 Wireshark 里能看到大量 HTTP 流量、Firefox 那边的 Burp 拦截面板跳出了请求,就说明整个实验的数据通路已经完全打通。请注意,Burp 拦截模式默认是打开的,看到请求被暂停在面板里是正常现象,点击Forward按钮放行即可。
3. 协议分析:把 HTTP 和 Cookie 看穿
3.1 一次登录请求的前世今生
协议分析不是单纯地"抓包看看",而是要能讲清楚一个完整请求从用户按下回车到页面渲染,中途经历了哪几层协议、每个字段是什么意思。我在这次实验里,把下面四步完整过了一遍,每一步都在 Wireshark 里有对应证据。
第一步是 DNS 解析。浏览器先要把10.10.10.10这个 IP 解析出来——因为这里用的是 IP 直连,DNS 界面很简单,但如果换成域名,就能在抓包里看到 DNS 请求和响应包。前置的头歌平台上做过的 DNS 协议分析实验在这里直接派上了用场。
第二步是 TCP 三次握手。抓包列表里最显眼的就是三个连续的数据包:SYN、SYN-ACK、ACK。这个过程的直观价值在于,它让你意识到"连接建立"和应用层数据发送是分开的两件事,HTTP 请求只是在三次握手完成之后,通过这个已经建立的可靠通道发送的数据。
第三步是 HTTP 请求与响应。Wireshark 里用过滤条件http就能把应用层流量筛出来。点开一个 POST 请求包,能看到请求行、头部字段和数据体。第四步是浏览器渲染,这一步不在抓包范围内,但值得心里过一遍:浏览器拿到 HTML、CSS、JavaScript 之后再展示给用户。
我建议你在做协议分析时不要只看 Wireshark 的解析结果,而是右键把"原始数据"复制出来,用十六进制和 ASCII 对照着看一遍。你会直观地看到 HTTP 头部其实都是明文,Cookie 字段就这样赤裸裸地躺在数据包里。这也是后面会话劫持能成立的物理基础。
3.2 Session 与 Cookie 的工作机制
HTTP 协议本身是"无状态"的,意思是服务器处理完一个请求后,不会自动记住这个客户端是谁。但 Web 应用几乎都有登录功能,登录成功之后服务器得知道"接下来这段对话属于 admin 这个用户",于是 Session 机制出现了。
整个机制可以缩成一句话:用户登录成功后,服务器在内存或数据库里创建一个会话对象,生成一个随机字符串作为 Session ID,通过响应头Set-Cookie: PHPSESSID=xxxx下发给浏览器;浏览器再次请求时,在请求头里带上Cookie: PHPSESSID=xxxx,服务器根据这个 ID 查出对应的会话对象,才知道当前用户是谁。
我在 DVWA 环境里用登录请求验证了这一点。响应包里清清楚楚写着 Set-Cookie 头,请求包里则有对应的 Cookie 头。这里值得写一段类比:Cookie 就像你进游泳馆时发的手环,手环上的号码就是 Session ID,服务台那边登记着号码对应的人是哪个会员。服务员不认人脸,只认手环号码。会话劫持的本质,就是捡到或偷看到别人的手环号码,然后让服务员用这个号码去服务台查出对方的信息。
3.3 抓包实操:分析一次完整登录
这部分我逐步记录了自己的实际抓包过程。先清空浏览器缓存和历史记录,打开 Wireshark 选择仅主机网卡,过滤条件设为http && ip.addr == 10.10.10.10。接着打开无痕窗口访问 DVWA 登录页,输入 admin / password,点击登录,然后回到 Wireshark 停止抓包。
抓包结果里按顺序能看到次数不多、但信息量很足的请求。第一个是 GET 请求登录页面,第二个是 POST 提交账号密码。点开 POST 包里的HTML Form URL Encoded字段,能看到username=admin&password=password,数据体是明文的。响应包里则有两个关键头:Location: index.php表示登录成功跳转,Set-Cookie: PHPSESSID=XXXX表示服务端下发了会话凭据。
同样的流量在 Burp Suite 里看起来更舒服。HTTP History 面板能按时间列出所有经过的请求和响应,点开任一条就能看到完整的头和体。我第一次做的时候,两边对照着看,很快记住了一件事:服务器识别身份并不靠请求里的用户名,它只认 Cookie 里的 PHPSESSID 值。这个认知直接决定了后面实验的操作方式。
4. 会话劫持实验:在靶场上完整复现
4.1 劫持原理:为什么 Cookie 就是"身份凭证"
会话劫持(Session Hijacking)的教科书定义是:攻击者通过某种手段获取合法用户的 Session ID,然后使用该 ID 与服务器交互,从而伪装成该用户执行操作。
原理听起来简单,但每一步都需要落到协议细节上。首先,Session ID 必须通过某种方式从浏览器传到服务器,这个传递通道如果是明文 HTTP,局域网内任何一台设备上的抓包工具都能看到完整的 Cookie 头。其次,服务器默认把收到的 Session ID 当作有效凭据,不校验请求来源是否真的是当初领取该 Session ID 的浏览器。最后,只要攻击者拿到的 Session ID 还没过期,他就能一直以受害者的身份访问应用。
我当时的实验思路是:先让浏览器 A 登录 DVWA 拿到一个合法的 PHPSESSID,然后在浏览器 B 里把这个 PHPSESSID 写入 Cookie,如果刷新后 B 直接进入登录状态,就说明"服务器只认 Session ID,不认客户端"这个假设被验证了。实验本身不需要注入、不需要破解任何东西,就是直接使用了协议的设计逻辑,特别适合用来建立"协议信任可以被滥用"的安全直觉。
提示:本实验完全用于本地靶场教学环境,会话劫持手法不应在任何未授权系统上尝试。安全测试的基本原则是"先授权,后测试",这个习惯从入门第一天就要养成。
4.2 复现步骤全记录:从复制 Cookie 到修改重放
具体操作我拆成了五个步骤,每一步都有明确的观察目标。
第一步,在 Firefox 里打开 DVWA 登录页,登录成功。登录完成后不要关页面,调出 Cookie-Editor 插件,可以看到当前 Cookie 列表里有一个名字为PHPSESSID的项,点击它查看 value,复制这串值。这个值就是服务器分配给当前浏览器的会话编号。
第二步,打开 Firefox 的另一个无痕窗口(相当于"另一个浏览器"),访问http://10.10.10.10/dvwa/login.php。这时候它是未登录状态,页面停留在登录表单。打开 Cookie-Editor,把刚才复制的 PHPSESSID 值作为一个新 Cookie 写入这个窗口,Domain 填10.10.10.10,Path 填/。
第三步,在同窗口里直接访问http://10.10.10.10/dvwa/index.php。按 F5 刷新,页面直接进入了 admin 的登录后界面,没有出现登录表单。到这一步,复现已经成功了:第二个浏览器拿到了第一个浏览器的 Session ID,服务端认为它们是同一个用户。
第四步,用 Burp 把这条链路再做一遍来加深理解。回到正常窗口,先在 Burp 里确认拦截开关打开,然后刷新 DVWA 页面。当请求停在 Burp 的拦截面板时,找到Cookie头,手动把它改成第一步里记录的 PHPSESSID 值,再点 Forward 放行。页面同样进入了登录状态。
第五步,做一次对照实验。在 Wireshark 里再次抓包,对比未登录请求和登录后的请求。未登录请求的 Cookie 头要么不存在,要么是服务器新下发的陌生 Session ID;登录后的请求,Cookie 头和浏览器的 PHPSESSID 一一对应。如果翻看响应包,还能看到Set-Cookie里是否有HttpOnly、Secure、SameSite这些属性,它们直接决定了劫持能否得手。
我建议你把步骤 3 的刷新操作重复几遍,每次刷新都确认页面状态。你会发现攻击的价值在于"持久性":只要服务器端的会话没过期,被伪造的 Session ID 就能一直使用,这比一次性注入的攻击更有威胁。
4.3 从攻击反推防御:为什么 HTTPS 和 HttpOnly 能挡住攻击
完成复现后,我强烈建议你做一次"防御视角回看",否则这个实验的意义就削弱了一半。会话劫持的根源在于 Cookie 数据被明文传递、Session ID 能被第三方读取。顺着这个思路,防御手段其实是可以推理出来的。
第一个手段是启用 HttpOnly 属性。它的作用是禁止 JavaScript 读取document.cookie。注意它防的不是抓包,而是 XSS 攻击——即使攻击者注入了脚本,也无法直接拿到 Cookie 值。这个属性对"抓包式劫持"没用,但防住了 XSS 这条最常见的窃取路径。
第二个手段是启用 Secure 属性。这个属性告诉浏览器:只有在 HTTPS 连接下才允许把这个 Cookie 发出去。加上 HTTPS 加密后,即使 Wireshark 在同一网段抓包,看到的也是 TLS 密文,Session ID 不会以明文形式暴露。攻击者拿不到可用的 Cookie,上一节那些修改重放的操作就全都不成立了。
第三个手段是缩短会话生命周期。服务端设置不活跃超时时间,比如 20 分钟后自动销毁 Session;登录成功后立即重置 Session ID,防止"会话固定"攻击——也就是攻击者先把自己拿到的 Session ID 塞给受害者,等受害者登录成功后,再用同一个 ID 顶替进去。DVWA 高安全级别会展示部分这些配置的作用,你不妨把 DVWA Security 从 low 切到 high,重新做一遍同样的操作,看看哪里开始行不通了。
这些手段我整理成了一张对照表,方便你理解每个防御点对应哪种攻击路径。
| 防御手段 | 作用链路 | 防住的攻击 | 防不住的攻击 |
|---|---|---|---|
| 全站 HTTPS + Secure Cookie | 传输加密 | 明文抓包窃取 Cookie | 本机被控后的直接读取 |
| HttpOnly | 禁止脚本读 Cookie | XSS 窃取 Cookie | 抓包、中间人 |
| SameSite | 限制跨站携带 Cookie | 部分 CSRF | 同站内的恶意操作 |
| 会话超时 / 登录后重置 Session ID | 缩短有效时间窗口 | 长期复用旧 ID | 瞬时窗口内的重放 |
| 异常检测 / 绑定 IP、设备指纹 | 增加攻击者伪装成本 | 大范围 Cookie 盗用 | 伪造指纹的定向攻击 |
5. 常见问题与排查技巧实录
5.1 实验中的高频报错与解决办法
这个实验虽然步骤清晰,但我在实际操作中还是踩了不少坑,也帮同学排查过几次。下面这五个问题是最常出现的,整理成速查表供你直接对照。
| 问题现象 | 可能原因 | 排查思路和解决动作 |
|---|---|---|
| 浏览器访问 10.10.10.10 拒绝连接 | 靶机 Apache 没启动,或网卡 IP 配错 | 先在靶机上执行ip addr确认 IP,再sudo systemctl status apache2看服务状态 |
| DVWA 页面提示无法连接数据库 | MySQL 账号密码没同步到 config 文件 | 核对config.inc.php里的数据库用户名和密码,用 mysql 客户端命令行测试连接 |
| DVWA 页面白屏没有按钮 | config 文件缺失或目录权限不足 | 确认存在config.inc.php,并给hackable/uploads目录设置 777 权限 |
| 浏览器访问时 Wireshark 里看不到 HTTP 流量 | 抓包网卡选错,或浏览器走了缓存 | 重新选择仅主机网卡,清浏览器缓存后强制刷新,过滤条件换成tcp.port == 80试试 |
| Burp 拦截面板里没有请求 | 浏览器没有配置到 Burp 监听端口 | 确认 Firefox 连接设置里 HTTP/HTTPS 都填了 127.0.0.1:8080,Burp 的监听状态是 Running |
| 修改 Cookie 后仍然无法进入登录状态 | 复制的 PHPSESSID 不对或会话已过期 | 重新登录一次,用 Cookie-Editor 核对域名和路径字段,改完直接访问 index.php 刷新 |
除了表里的问题,还有个隐蔽的小坑:如果你用的是 Chrome 而不是 Firefox,Burp 配置到系统代理之后 Chrome 可能不走自定义设置,而且 Chrome 对自签名证书的管理比 Firefox 麻烦。Firefox 做这种安全实验的体验明显更顺,我建议全程统一用 Firefox,避免工具兼容性问题消耗时间。
5.2 避坑技巧与个人实操心法
几个容易被忽略的操作细节,值得单独拿出来说。第一,做会话劫持实验时,两个浏览器窗口一定要隔离 Cookie 存储,最好一个普通窗口一个无痕窗口,否则浏览器共享 Cookie 会导致"第二个窗口不需要改也能进入登录状态"的假象。第二,Wireshark 抓包时如果数据量太大,先按tcp.stream eq 0只看第一对 TCP 连接,一条流一条流地分析,比全部混在一起看高效得多。第三,修改 Cookie 值的实验,动作最好慢一点、分步做——先看服务端响应,再改请求,再观察效果,形成完整的因果链。
我自己在整个实验里最深的体会是:安全攻击一点也不神秘,它就是利用设计者没有意识到的信任假设。DVWA 靶场里低安全级别和普通站点的差别,往往只是一个Secure标志位或者一道 HTTPS 配置。"攻击者能做到哪一步",很大程度上取决于"应用开发者少做了哪一步",这才是这门实验真正想传递的思维方式。
实验做完之后,如果你想继续往里走,我建议两个方向。一是去玩 CTF 的 Web 入门题,很多题目本质上就是在练习协议分析加 Cookie 利用,ctfshow 这类平台上有系统的 Web 技能树,配合这次实验建立的思路会顺手很多。二是从攻击视角转向防御视角,用 Acunetix 这类漏洞扫描器去扫描 DVWA,对照报告里描述的漏洞成因,把你四十分钟就能复现的实验过程,变成三十秒就能识别的风险画像。这条路走通之后,Web 安全的大门才算真正推开。