DVWA靶场通关笔记-反射型XSS(Impossible级别)
目录
一、反射型XSS
二、源码分析
1、index.php
2、Impossible.php
3、htmlspecialchars功能函数
三、反射型XSS安全级别分析
1、Low 级别
2、Medium 级别
3、High 级别
4、Impossible 级别
四、Impossble防范分析
1、使用htmlspecialchars函数进行输入编码
2、引入 Anti-CSRF 令牌验证机制
3、严格的输入验证与输出过滤结合
本系列为通过《DVWA靶场通关笔记》的反射型XSS关卡(low,medium,high,impossible共4关)渗透集合,通过对相应关卡源码的代码审计找到讲解渗透原理并进行渗透实践。本文为反射型XSS impossible关卡的原理分析部分,讲解相对于low、medium和high级别,为何对其进行渗透测试是Impossible的。
一、反射型XSS
反射型 XSS(Cross-Site Scripting)又称非持久型 XSS,是一种常见的跨站脚本攻击类型,其核心特点是恶意脚本通过用户的单次请求注入,并由服务器反射回页面执行,不经过服务器持久化存储。反射型XSS的攻击流程如下所示。
- 构造恶意链接:攻击者将包含恶意 JavaScript 代码的链接(如 URL 参数)发送给目标用户。
- 用户触发请求:用户点击链接后,请求被发送到有XSS安全风险的服务器。
- 服务器反射响应:服务器未对输入进行有效过滤,直接将恶意代码作为响应的一部分返回给用户浏览器。
- 脚本执行:用户浏览器解析并执行恶意脚本,导致攻击者窃取 cookie、会话令牌等敏感信息,或执行伪造操作。
二、源码分析
1、index.php
进入DVWA靶场源目录,找到index.php源码。
这段代码是DVWA靶场中反射型XSS攻击的演示页面,主要功能如下所示。
-
初始化设置
-
定义系统路径常量,加载必要文件,启动DVWA环境(含用户认证和安全检测)。
-
-
安全等级控制
-
根据用户Cookie中的
security
值(low/medium/high/impossible)动态加载不同防御级别的代码文件(low.php
/medium.php
/high.php
/impossible.php
)。
-
-
反射型XSS测试界面
-
生成一个表单,用户输入
name
参数并提交,服务端将输入反射到页面中(具体逻辑在引入的不同级别文件中实现)。 -
在最高防御等级(impossible)时添加CSRF令牌。
-
-
动态内容渲染
-
变量
$html
由引入的不同文件生成,用于演示不同安全等级下的反射型XSS攻击效果。
-
详细注释后的代码如下所示。
<?php// 定义DVWA根目录路径常量define(\'DVWA_WEB_PAGE_TO_ROOT\', \'../../\');// 引入DVWA核心页面初始化文件require_once DVWA_WEB_PAGE_TO_ROOT . \'dvwa/includes/dvwaPage.inc.php\';// 启动DVWA页面,要求用户已认证并启用PHPIDS(安全检测)dvwaPageStartup(array(\'authenticated\', \'phpids\'));// 创建新页面对象$page = dvwaPageNewGrab();// 设置页面标题(包含名称和默认分隔符)$page[\'title\'] = \'Vulnerability: Reflected Cross Site Scripting (XSS)\' . $page[\'title_separator\'] . $page[\'title\'];// 设置页面ID(用于标识当前页面)$page[\'page_id\'] = \'xss_r\';// 设置帮助按钮和查看源码按钮的链接目标$page[\'help_button\'] = \'xss_r\';$page[\'source_button\'] = \'xss_r\';// 连接数据库dvwaDatabaseConnect();// 根据安全等级选择对应的级别文件$vulnerabilityFile = \'\';switch($_COOKIE[\'security\']) { case \'low\': $vulnerabilityFile = \'low.php\'; // 低安全等级 break; case \'medium\': $vulnerabilityFile = \'medium.php\'; // 中安全等级 break; case \'high\': $vulnerabilityFile = \'high.php\'; // 高安全等级 break; default: $vulnerabilityFile = \'impossible.php\'; // 最高防御等级 break;}// 引入对应安全等级的代码文件require_once DVWA_WEB_PAGE_TO_ROOT . \"vulnerabilities/xss_r/source/{$vulnerabilityFile}\";// 构建页面主体HTML$page[\'body\'] .= \" Vulnerability: Reflected Cross Site Scripting (XSS)
What\'s your name?
\\n\";// 如果是最高防御等级,添加CSRF令牌if($vulnerabilityFile == \'impossible.php\') $page[\'body\'] .= \" \" . tokenField();// 继续构建页面(包含动态生成的HTML内容和参考资料链接)$page[\'body\'] .= \" {$html} More Information
- \" . dvwaExternalLinkUrlGet(\'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)\') . \"
- \" . dvwaExternalLinkUrlGet(\'https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet\') . \"
- \" . dvwaExternalLinkUrlGet(\'https://en.wikipedia.org/wiki/Cross-site_scripting\') . \"
- \" . dvwaExternalLinkUrlGet(\'http://www.cgisecurity.com/xss-faq.html\') . \"
- \" . dvwaExternalLinkUrlGet(\'http://www.scriptalert1.com/\') . \"
\\n\";// 输出最终生成的HTML页面dvwaHtmlEcho($page);?>
2、Impossible.php
进入DVWA靶场源目录,找到Impossible.php源码,打开源码Impossible.php,如下所示。
Impossible的功能如下所示。
- 输入检查:验证
name
参数是否存在且非空。 - CSRF防护:通过
checkToken
验证用户令牌与会话令牌是否匹配。 - XSS防护:使用
htmlspecialchars
对用户输入进行HTML实体编码。 - 安全输出:将编码后的内容嵌入HTML的
- 令牌更新:每次请求后生成新令牌,防止重复使用。
详细注释后的源码如下所示。
<?php// 检查是否存在名为\"name\"的GET参数且其值不为NULLif(array_key_exists(\"name\", $_GET) && $_GET[\'name\'] != NULL) { // 验证Anti-CSRF令牌(防止跨站请求伪造) checkToken($_REQUEST[\'user_token\'], $_SESSION[\'session_token\'], \'index.php\'); // 获取用户输入,并使用htmlspecialchars进行HTML实体编码 $name = htmlspecialchars($_GET[\'name\']); // 将安全处理后的用户输入拼接到HTML中 $html .= \"
Hello ${name}\";}// 生成新的Anti-CSRF令牌(用于下一次请求验证)generateSessionToken();?>
3、htmlspecialchars功能函数
htmlspecialchars
是 PHP 中用于处理 HTML 特殊字符的重要函数,主要作用是将可能影响 HTML 解析的特殊字符转换为对应的 HTML 实体,从而防止跨站脚本(XSS)等注入攻击。默认情况下,htmlspecialchars()
处理以下关键字符。原字符 转换后的HTML实体 转换目的 &
(和号)&
防止混淆为实体的开始 \"
(双引号)"
防止跳出 HTML 属性(如 href=\"user_input\"
)\'
(单引号)'
(或'
)防止跳出使用单引号的 HTML 属性(如 href=\'user_input\'
)<
(小于号)<
防止新 HTML 标签的开始 >
(大于号)>
防止新 HTML 标签的结束 htmlspecialchars函数定义如下所示。
htmlspecialchars( string $string, int $flags = ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, ?string $encoding = null, bool $double_encode = true): string
其中flags的常用含义如下所示。
常量 值 描述 安全等级 ENT_COMPAT 2 仅转换双引号,不转换单引号 中等 ENT_QUOTES 3 转换双引号和单引号 高(推荐) ENT_NOQUOTES 0 不转换任何引号 低(不安全) 三、反射型XSS安全级别分析
四个安全级别(Low、Medium、High、Impossible)在 反射型 XSS 防护上的区别如下所示。
1、Low 级别
Low 级别完全没有防护措施,代码直接将用户通过 GET 请求传入的 “name” 参数值拼接进 HTML 输出。这意味着攻击者攻击者可以构造包含恶意脚本的 URL,例如
?name=alert(document.cookie)
,当用户点击该链接时,脚本会被浏览器直接执行。因为没有任何过滤或编码处理,任何输入都会被当作原样解析,极易引发 XSS 攻击,窃取用户 cookie 等敏感信息。2、Medium 级别
Medium 级别尝试通过
str_replace
函数移除输入中的字符串,但该过滤过滤区分大小写且仅针对完整的
标签。攻击者可通过大小写混合(如
)绕过过滤,也能使用
<script>
这类拆分标签的方式,让过滤后残留有效脚本标签。例如?name=alert(\"XSS\")
,经过处理后仍会保留可执行的脚本部分,无法彻底防御 XSS。3、High 级别
High 级别使用正则表达式
preg_replace
过滤含 “script” 字符组合的输入(不区分大小写),试图阻断所有与script
相关的标签。但这种方式只能防御依赖script
标签的攻击,无法应对 HTML 事件注入。攻击者可利用onclick
onerror
等事件,构造如?name=
的 payload,无需script
标签即可触发恶意代码执行,仍存在 XSS安全风险。4、Impossible 级别
Impossible 级别采用双重防护:一是用
htmlspecialchars
函数将用户输入的特殊字符(如<
>
)转换为 HTML 实体,确保输入被当作纯文本处理,从根源上阻止脚本解析;二是引入 Anti-CSRF 令牌机制,通过checkToken
验证请求合法性。即使攻击者尝试注入脚本,也会被编码为普通文本,且令牌验证能防止跨站请求伪造,两种措施结合可有效防御各类反射型 XSS 攻击。四、Impossble防范分析
Impossible 级别通过多重机制实现了对反射型 XSS 的彻底防御,核心措施包括输入编码处理和 Anti-CSRF 令牌验证,两者结合形成了完整的安全防护体系。
1、使用
htmlspecialchars
函数进行输入编码原理:
htmlspecialchars
函数能将 HTML 中的特殊字符(如<
、>
、&
、\"
、\'
等)转换为对应的 HTML 实体(如<
转为<
、>
转为>
)。这样一来,用户输入的内容会被当作纯文本处理,而非可执行的 HTML 或 JavaScript 代码,从根本上阻止了 XSS 攻击中恶意脚本的注入与执行。// 获取用户输入并进行编码处理$name = htmlspecialchars($_GET[\'name\']);// 将处理后的内容输出到页面$html .= \"
Hello ${name}\";
当用户输入
alert(\"XSS\")
时,经过htmlspecialchars
处理后,会被转换为<script>alert("XSS")</script>
,浏览器会将其作为普通文本显示,而非执行脚本,有效阻断 XSS 攻击。2、引入 Anti-CSRF 令牌验证机制
原理:跨站请求伪造(CSRF)常与 XSS 结合实施攻击,而 Anti-CSRF 令牌通过在请求中加入随机生成的令牌,验证请求来源的合法性。服务器会在用户会话中存储令牌,当客户端提交请求时,需同时发送该令牌,服务器验证令牌一致性后才处理请求,防止攻击者伪造合法用户的请求。
// 验证CSRF令牌checkToken($_REQUEST[\'user_token\'], $_SESSION[\'session_token\'], \'index.php\');// 生成并存储新的CSRF令牌generateSessionToken();// 在表单中嵌入令牌字段function tokenField() { $token = $_SESSION[\'session_token\']; return \"\";}
在impossible.php中,表单提交时必须包含
user_token
字段,其值与服务器存储的session_token
一致才会被处理。即使攻击者通过 XSS 获取了用户 cookie,若无法获取实时令牌,也无法伪造有效请求,提升了整体安全性。3、严格的输入验证与输出过滤结合
原理:除编码外,
impossible
级别通过 “输入验证 + 输出过滤” 双重机制确保安全。输入验证检查用户输入是否符合预期格式(如长度、字符类型等),过滤掉不符合规则的内容;输出过滤则在数据呈现到页面时再次处理,即使输入验证存在疏漏,输出过滤也能作为最后一道防线,防止恶意代码执行。// 输入验证:限制输入长度并检查字符类型if (array_key_exists(\"name\", $_GET) && $_GET[\'name\'] != NULL) { $rawName = $_GET[\'name\']; // 仅允许字母、数字和部分安全符号 if (preg_match(\'/^[a-zA-Z0-9_\\- ]+$/\', $rawName)) { // 输出过滤:再次使用htmlspecialchars编码 $name = htmlspecialchars($rawName); $html .= \"
Hello ${name}\"; } else { $html .= \"
Invalid input\"; }}
该机制先通过正则表达式限制输入内容,拒绝包含特殊字符的恶意输入;再通过
htmlspecialchars
进行输出编码,双重保障确保用户输入无法被解析为恶意代码,彻底消除 XSS 风险。