JSP页面如何有效防范无HTML特征的JavaScript注入攻击?
问题根因
<c:out escapeXml="true">的防护范围仅限HTML上下文——它只会转义<、>、&、"、'这类HTML语法特殊字符,避免用户输入突破HTML文本、普通HTML属性的边界。你遇到的防护失效本质是上下文错配:你把经过HTML转义的参数直接输出到了<script>标签内的JavaScript代码段、或者onclick这类事件属性的JS执行上下文里,而测试payloadtest'+alert(6853)+'本身不包含任何需要HTML转义的字符,自然可以直接闭合你代码里的JS字符串边界,触发代码执行。
这种场景和普通HTML注入的XSS不是一个类型,靠HTML转义完全防不住。
可落地修复方案
按优先级从高到低排列:
- 优先彻底避免把用户可控值直接内嵌到JS代码块中
这是零成本、几乎不会出错的根治方案。如果需要把后端参数传递给前端JS,不要直接在<script>里拼字符串,把参数放到HTML标签的自定义data-*属性中,属性值用<c:out>做标准HTML转义,前端JS通过DOM API读取属性值使用即可。安全示例代码:
这种实现下,哪怕参数里带完整的JS恶意代码,也只会被当做纯字符串读取,永远不会被解析执行。<!-- 参数放在HTML属性上下文,c:out转义完全生效 --> <div id="paramHolder" data-target-value="<c:out value='${stringValue}' escapeXml='true'/>" hidden></div> <script> // 纯文本读取,不存在代码执行风险 const stringValue = document.getElementById('paramHolder').dataset.targetValue; // 后续业务逻辑直接使用该变量即可 </script> - 必须在JS上下文输出用户值时,使用专用的JS字符串转义规则,禁止复用HTML转义
不要手写转义逻辑,直接使用成熟的通用安全转义库提供的JavaScript字符串转义能力,对要输出到JS段的变量做转义处理:把单引号、双引号、反斜杠、换行、回车、制表符、</以及非打印控制字符全部转义为\xHH或\uHHHH格式的转义序列,确保用户输入永远无法突破JS字符串的边界。
注意:哪怕做了JS转义,也严禁将用户可控值传入eval()、setTimeout(string)、new Function()这类会把字符串当做代码解析执行的API,否则依然存在注入风险。 - 配置全局兜底防线
给所有响应添加合适的Content-Security-Policy响应头,默认禁止内联脚本执行、禁止非信任域名的脚本资源加载,就算个别点位存在转义遗漏,CSP也会直接拦截恶意JS的执行,是非常可靠的最后一道防护。
另外不要在全局入参层做统一XSS过滤,这种方式很容易破坏合法业务数据,正确的做法是输出时按照所在上下文做对应转义,不存在能通吃HTML、JS、CSS、URL等所有上下文的通用转义规则。
避坑提醒
- 不要用关键字黑名单做防护,比如拦截
alert、script这类字符串,攻击者可以通过Unicode编码、大小写变形、括号拼接等几十种方式轻松绕过,黑名单防护本质是不可靠的。 - 不要认为不包含
<>这类HTML特殊字符的输入就是安全的,你遇到的场景已经证明:纯JS语法字符在错误的上下文里,一样可以形成可执行的注入。 - 白名单校验只适合固定枚举值的参数场景,对于可以接收任意合法字符串的参数,严格按上下文转义才是通用解决方案。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

