JSP+JS站点backURL参数XSS修复方案安全性验证及两种实现对比问询
方案安全性评估
两种方案都无法完全抵御XSS攻击,其中第二种方案完全无防护效果。
第二种方案:完全不安全
你直接把未做任何编码的${param.backUrl}插入到onclick事件的单引号包裹的参数位置,攻击者只需要构造如下的backUrl参数就能直接触发XSS:
');alert(document.cookie);//
插入到页面后实际的onclick内容会变成:
onclick="goback(this,'');alert(document.cookie);//')"
单引号被直接闭合,恶意脚本会直接执行,没有任何防护能力。
第一种方案:存在严重安全缺陷
虽然你用了OWASP Java Encoder的e:forHtml对参数做了HTML实体编码,但是你后续自定义的decodeEntity函数把编码后的内容又还原回原始字符串了,等于编码操作完全白费。
就算你不解码,直接把编码后的内容赋值给href,还有另一个风险:如果攻击者构造javascript:alert(1)作为backUrl参数,赋值给href之后用户点击按钮就会执行恶意脚本,HTML实体编码对这种伪协议的攻击完全无效。
最优修复方案
根据业务场景选择对应方案:
- 如果「返回」按钮的功能就是回到浏览器历史的上一页,不需要业务自定义返回地址:直接把点击逻辑改成调用
history.back(),完全不用传递backUrl参数,从根源消除这个XSS风险点,代码示例:
<a class="float_left button" href="javascript:void(0)" onclick="history.back()">Retour</a>
- 如果确实需要通过backUrl参数指定业务自定义的返回地址,按以下步骤改造:
- 调整编码方式:如果要把参数插入到JS字符串中,使用
e:forJavaScript而非e:forHtml编码,不要自行做解码操作。 - 增加URL合法性校验:赋值给href之前必须检查URL格式,只允许相对路径、或者本域名/可信域名的http/https协议链接,禁止
javascript:、data:、vbscript:等危险伪协议,校验逻辑示例:
function goback(domEle, backUrl) { const allowedProtocols = ['http:', 'https:']; let url; try { url = new URL(backUrl, window.location.origin); } catch (e) { domEle.href = '/'; return; } if (!allowedProtocols.includes(url.protocol) || url.origin !== window.location.origin) { domEle.href = '/'; return; } domEle.href = backUrl; }
- 更安全的参数传递方式:不要把参数直接塞到内联事件的参数里,改为存在HTML的data属性中,用
e:forHtml编码即可,浏览器读取data属性时会自动处理实体编码,避免内联事件的注入风险:
<a class="float_left button" href="javascript:void(0)" data-backurl="${e:forHtml(param.backUrl)}" id="backBtn">Retour</a>
JS中绑定事件读取参数:
document.getElementById('backBtn').addEventListener('click', function() { const backUrl = this.dataset.backurl; // 执行上述URL校验逻辑后再赋值跳转 })
内容的提问来源于stack exchange,提问作者Sébastien Sutterlin
相关产品推荐
相关产品推荐

