web安全 - XSS防御理念
要使XSS攻击成功,攻击者需要在网页中插入和执行恶意内容。web应用程序中的每个变量都需要受到保护,
确保所有变量都经过验证,然后被转义编码或者清理过滤,这就是完美的抗注入性。任何未经过此过程的
变量都是潜在的弱点。
框架使确保变量得到正确验证和转义或清理变得容易,然而框架往往并不完美,在React 和 Angular等流行
框架中仍然存在安全漏洞,输出编码和HTML清理有助于解决这些问题。
1. 输出编码
输出编码的目的是将不受信任的输入转换未安全的的形式,在这种形式中,输入作为数据显示给用户,而不
是在浏览器中作为代码执行。
- 输出编码规则
编码类型 | 编码机制 |
---|---|
HTML实体编码 | & => & < => < > => > " => " ' => ' / => / |
HTML属性编码 | 除字母数字字符外,使用HTML实体 &#xHH; 编码所有字符格式,包括空格。(HH = 十六进制) |
URL编码 | 标准百分比编码,URL编码应该只用于编码参数值,而不是整个URL或路径片段 |
Javascript 编码 | 除字母数字字符外,使用\uXXXX unicode编码格式(X = 整数)对所有字符进行编码 |
CSS十六进制编码 | CSS编码支持\XX 和\XXXXXX 两种格式,如果下一个字符继续编码序列,则两个字符的编码会出现问题。一种解决方案是在编码后添加一个空格, 第二种是建议使用全编码格式。 |
- 在不同的上下文中进行安全编码
数据类型 | 上下文 | 代码示例 | 编码防御 |
---|---|---|---|
字符串 | HTML标签内 | <span> Untrusted Data </span> | HTML实体编码 |
字符串 | 安全的HTML属性 | <input type="text" name="fname" value="Untrusted Data"> | HTML属性编码 |
字符串 | URL参数 | <a href="/site/search?value=Untrused data"> clicke me</a> | URL编码 |
字符串 | href或者src属性中不可信的URL | <a href="Untrusted Data" > click me <iframe src="Untrusted Data" /> | 规范输入,URL验证,仅允许http 和https协议,进行属性编码 |
字符串 | CSS值 | <div style="width:Untrusted Data "> Selection </div> | CSS十六进制编码 |
字符串 | javascript 变量 | <script> var currentValue='Untrusted Data';</script><script>someFunction('Untrusted Data');</script> | 确保用引号包裹javascript变量,javascript十六进制编码,javascript unicode编码,避免反斜杠编码(', ") |
HTML | HTML标签内 | <div> Untrusted HTML </div> | HTML清理 |
字符串 | Dom XSS | <script>document.write("Untrusted Input: " + document.location.hash );</script> | 使用安全的接收器,对不可信的数据根据上下文进行编码 |
2. HTML清理
有时用户需要编写HTML,一种情况是允许用户在所见即所得编辑器中更改内容的样式或结构。此处的输出
编码将防止XSS,但会破坏应用程序的预期功能,这时候应该使用HTML清理,它从变量中去除危险的HTML
并返回一个安全的HTML字符串。
注意:
- 如果对内容清理后,再对其进行修改,则可能会使清理工作无效。
- 如果对内容清理后,将其发送到库以供使用,则必须确保它不会以某种方式改变清理后的字符串,否则
清理会变得无效。 - 必须定期的修补正在使用的HTML清理库,比如DOMPurify。因为浏览器定期更改功能并发现被绕过。
3. 安全的接收器
安全专家讨论的源和接收器,如果你污染了一条河流,它就会流向下游某个地方。计算机安全也是如此,
XSS接收器就是将变量放入网页的地方,它们往往是DOM的一些API。安全的接收器将变量视为文本并且
永远也不会执行它。
下面是一些安全的接收器:
elem.textContent = dangerVariable;
elem.insertAdjacentText(dangerVariable);
elem.className = dangerVariable;
elem.setAttribute(safeName, dangerVariable);
formfield.value = dangerVariable;
document.createTextNode(dangerVariable);
document.createElement(dangerVariable);
使用不安全的接收器前对数据进行清理
elem.innerHTML = DOMPurify.sanitize(dangerVar);
4. 其他安全措施
- cookie 属性HttpOnly设置防止session cookie信息被客户端脚本读取
- CSP 内容安全策略
- WAF web应用防火墙