XSS漏洞分析:Content-Disposition头注入导致的反射型XSS

该PHP脚本未对用户可控的token参数做任何过滤或编码,直接拼入Content-Disposition响应头中,可被利用构造恶意文件名实现HTTP头注入,进而触发浏览器解析上下文中的XSS。

该PHP脚本未对用户可控的`token`参数做任何过滤或编码,直接拼入`Content-Disposition`响应头中,可被利用构造恶意文件名实现HTTP头注入,进而触发浏览器解析上下文中的XSS。

这段代码存在典型的HTTP头注入(Header Injection)引发的XSS漏洞,而非传统HTML上下文中的反射型XSS。关键问题在于:

$input = $_GET['token'];
$input = str_replace(array("\n", "\0"), '', $input); // 仅过滤换行和空字节,防护严重不足
header("Content-Disposition: attachment; filename='$input'");

虽然代码移除了\n和\0,但未过滤回车符\r、单引号'、双引号"、分号;等关键字符,攻击者仍可通过注入\r\n(CRLF)实现响应头分裂(CRLF Injection),从而注入任意HTTP头(如Content-Type、X-XSS-Protection),甚至操控后续响应体内容。

更隐蔽且实际可行的利用路径是:利用浏览器对Content-Disposition中畸形filename值的不一致解析。现代浏览器(如Chrome、Firefox)在处理如下请求时:

GET /test/2.php?token='"><script>alert(1)</script>

会将响应头解析为:

Content-Disposition: attachment; filename=''"><script>alert(1)</script>'

尽管服务端声明了attachment,但若用户手动取消下载、或浏览器因MIME类型推测失败而选择渲染响应体(尤其当响应无明确Content-Type: application/octet-stream时),则<script>alert(1)</script>可能被当作HTML执行——这正是Security StackExchange所讨论的Content-Disposition XSS场景的核心风险。

✅ 正确修复方式(三重防御):

示例加固代码:

<?php
require 'flag.php';

$token = $_GET['token'] ?? '';
// 白名单校验
if (!preg_match('/^[a-zA-Z0-9_]{1,64}$/', $token)) {
    http_response_code(400);
    exit('Invalid token');
}

// RFC 5987 兼容编码(推荐)
$encoded = rawurlencode($token);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename*=UTF-8''$encoded");
header("X-Content-Type-Options: nosniff");

echo "Hello. $token";
?>

⚠️ 注意:仅过滤\n\0远远不够;依赖客户端行为(如“用户是否点击保存”)的防御是不可靠的;所有用户输入进入HTTP头前必须严格转义或编码。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。