本文是 XSS防御检查单的翻译版本 https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
介绍
本文描述了一种恰当地使用输出转码或者转义(encoding or escaping)防御XSS攻击的简单积极模式。
尽管存在巨量XSS攻击方式,遵守一些简单的规则能够彻底防住这类严重的攻击。
本文不探讨XSS攻击的商业和技术影响。
reflected and stored XSS 可以被解决,只要在服务器端执行合适的验证和转义(validation and escaping)。推荐使用转义转码库(ESAPI or the Microsoft Anti-Cross Site Scripting Library),因为存在很多特殊案例。DOM Based XSS攻击可以被解决, 使用DOM based XSS Prevention Cheat Sheet的特定子集。
关于XSS攻击因素的检查单,请参考优秀的 XSS Cheat Sheet by RSnake. 更多的介绍浏览器安全和各种浏览器的背景,请参考 Browser Security Handbook.
在阅读本检查单前, 有必要了解基础的注入理论(Injection Theory.)。
一个积极的XSS防护模型
本文将HTML看做为一个模板,带有一些插槽(slot), 开发者可以将不可信数据放入插槽。这些插槽覆盖了绝大多数开发者可能将不可信数据放入的通用地方。将不可信数据放到HTML其他地方是不被允许的。 这是白名单模式, 拒绝不被明确允许的任何事情。
考虑到浏览器解析HTML的方式, 每种不同类型的插槽都有些许不同的安全规则。当你将不可信数据放入插槽,需要采取某些步骤,确保数据不会破坏插槽,进而进入上下文环境,允许代码执行。
某种意义上讲,这种方法将HTML文档看做是参数化的数据库查询 - 数据保存在指定位置, 使用转义与代码上下文隔离开来。
本文描述最通常的插槽类型,和将不可信数据安全地插入插槽的规则。基于各种不同说明,为XSS因素, 和对所有流行的浏览器执行大量的手动测试,我们确定这里提出规则是安全的。
插槽被定义,每一个插槽都有一些规则提供。开发者如果没有非常仔细的分析,不应该(SHOULD NOT)把数据放到其他的插槽中,这样保证他们的所作所为是安全的。浏览器解析是极其奇异的, 很多看似无害的字符在正确的上下文中变成巨大的漏洞。
为什么不能仅仅使用HTML实体转码不可信数据?
HTML实体编码是OK的,对于将不可信数据放到HTML文档体重,例如放到<div>中。
但是HTML实体编码是有问题的,对于将不可信数据放入<script>标签中的任何地方,或者事件处理属性(例如onmouseover),或者在CSS中, 后者在URL中。 所以即使你在任何地方使用HTML实体编码, 仍然可能存在XSS漏洞。你必须使用转义语法,对于你想将不可信数据插入的HTML部分。 这就是下面规则所涉及的全部。
你需要一个安全的转码库
写一个编码器不是特别困难, 但是存在不少隐藏的缺陷。 例如, 你可能在JS中使用转义快捷写法 \", 但是这个值是危险的, 并且可能被浏览器中嵌套的解析器误解。你也有可能忘记转义“转义字符”, 攻击者可以利用抵消你的安全性努力。OWASP推荐使用关注安全的编码库, 保证这些规则被合理实现。
OWASP ESAPI 项目创建了一个转义库, 使用各种语言实现, 包括 Java, PHP, Classic ASP, Cold Fusion, Python, and Haskell.
Microsoft提供了一个转码库, Microsoft Anti-Cross Site Scripting Library for the .NET platform.
XSS防御规则
下面的规则目的是为了防御你应用中的所有XSS。尽管这些规则不允许将不可信数据插入到HTML中任何位置, 但是其包括了绝大多数通常使用案例。你在你的组织中不必要允许所有规则的使用。很多组织发现允许使用规则1和2就足够了(Many organizations may find that allowing only Rule #1 and Rule #2 are sufficient for their needs.)。如果你发现有其他的环境,可以使用转义变为安全的, 请反馈的讨论页面。
不要简单地转义各种规则中例子的字符列表,只转义那些列表是不够的。
黑名单方法是非常脆弱的, 这些白名单规则,经过仔细的设计, 甚至提供保护浏览器将来引入的漏洞。
规则#0 不插入不可信数据, Except in Allowed Locations
第一个规则是拒绝一切(deny all)。 不要将不可信输入插入HTML文档中,除非它是 Rule #1 through Rule #5定义的插槽之一。
本规则的原因是,浏览器有很多奇怪的HTML上下文, 以至于规则列表变得非常复杂。
<script>...NEVER PUT UNTRUSTED DATA HERE...</script> directly in a script <!--...NEVER PUT UNTRUSTED DATA HERE...--> inside an HTML comment <div ...NEVER PUT UNTRUSTED DATA HERE...=test /> in an attribute name <NEVER PUT UNTRUSTED DATA HERE... href="/test" /> in a tag name <style>...NEVER PUT UNTRUSTED DATA HERE...</style> directly in CSS
Most importantly, never accept actual JavaScript code from an untrusted source and then run it.
规则#1 在插入不可信数据到HTML元素内容前,执行HTML转义
本规则对应,将不可信数据插入到HTML体中某些位置。包括正常的标签中,例如div, p, b, td, etc
很多web框架都提供了 HTML转义, 如下详述的字符, 但是这是绝对不够的,对于其它的HTML上下文,
你需要执行其它此处详述的规则,
<body>...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...</body> <div>...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...</div> any other normal HTML elements
转义下述字符,使用HTML实体编码方法, 可以阻止切换到任何执行环境,例如 script, style, or event handlers
使用HEX实体是被推荐的在规范中(Using hex entities is recommended in the spec.)。
除了XML中五个重要字符(&, <, >, ", ‘), 正向反斜杠也被包括进来, 因为其有助于闭合HTML标签。
& --> & < --> < > --> > " --> " ‘ --> ' ' is not recommended / --> / forward slash is included as it helps end an HTML entity
参考 ESAPI reference implementation ,查阅HTML实体转义和反转义
String safe = ESAPI.encoder().encodeForHTML( request.getParameter( "input" ) );
规则#2 在插入不可信数据到HTML元素通用属性前,执行属性转义
本规则, 对应将不可信数据插入HTML元素典型属性值中,例如 width, name, value, etc。
本规则,不适用复杂的HTML属性值, 例如 href, src, style, or any of the event handlers like onmouseover.
非常重要地说明 事件处理属性值的转义处理, 必须遵从 规则3!
<div attr=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...>content</div> inside UNquoted attribute <div attr=‘...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...‘>content</div> inside single quoted attribute <div attr="...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">content</div> inside double quoted attribute
除了数字和字母, 转义其他的任何ASCII值小于256的字符, 转义格式为 &#xHH; 或者使用 named entity如果存在, 此转义组织切换出属性范围。
此规则应用广泛, 由于开发者往往让属性值不带引号。 带有引号的属性值,只需要对相应的引号转义即可; 但是不带引号的属性值, 可能被很多字符破坏, 包括: [space] % * + , - / ; < = > ^ and |
参考 ESAPI reference implementation ,查阅HTML实体转义和反转义
String safe = ESAPI.encoder().encodeForHTMLAttribute( request.getParameter( "input" ) );
规则#3 在插入不可信数据到JS数据值前,执行JS转义
本规则,关注动态生成的JS代码 -- 包括 script代码块 和 事件处理属性。
唯一安全放置不可行数据到代码中的方法是 放到引用的 数据值字符串中,例如 "data value."
在任何其它JS环境中插入不可信数据都是危险的, 因为其非常容易进入执行环境, 使用如下字符(包括但是不限与):
semi-colon, equals, space, plus, and many more
所以使用上格外小心
<script>alert(‘...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...‘)</script> inside a quoted string <script>x=‘...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...‘</script> one side of a quoted expression <div onmouseover="x=‘...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...‘"</div> inside quoted event handler
!!! 请注意, 存在一些JS函数, 它不可能安全地使用不可信数据, 即使使用 JS转义 (EVEN IF JAVASCRIPT ESCAPED!)
例如
<script> window.setInterval(‘...EVEN IF YOU ESCAPE UNTRUSTED DATA YOU ARE XSSED HERE...‘); </script>
除了 字母数字, 其他任何小于二五六的字符都要进行转义, 转义的格式为 \xHH, 防止切换出数据值范围, 到脚本环境, 或者进入另外一个属性。
不要使用转义捷径 \" , 因为HTML中使用一号作为 属性值范围标识。
这个转义捷径, 还容易遭受 "escape-the-escape" 攻击, 例如攻击者发送了 \", 解析器翻译为 \\"
这样就激活了 引号作为 属性值范围 的作用了。
如果事件处理句柄值使用引号括起来的, 那么破除这个环境需要使用引号。
但是我们有意使得此规则影响广泛, 因为开发者常常会将引号省略。
没有带引号的属性, 可以被一下字符破除环境 , 包括但是不限于 [space] % * + , - / ; < = > ^ and |
同时, </script> closing tag会关闭一个script块, 尽管它是出现在双引号中, 因为HTML解析器比JS解析器执行靠前。
参考 ESAPI reference implementation ,查阅JS转义和反转义
String safe = ESAPI.encoder().encodeForJavaScript( request.getParameter( "input" ) );
规则#3.1 在HTML环境中执行HTML转义,并使用JSON.parse读取数据
暂时无研究, 待添加
规则#4 在插入不可信数据到HTML style属性值之前,执行CSS转义并严格校验
暂时无研究,待添加
规则#5 在插入不可信数据到URL参数值之前,执行URL转义
本规则,应对将不可信数据插入URL中,一般是HTTP GET 参数。
<a href="http://www.somesite.com?test=...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">link</a >
除了字母数字, 其他任何小于256的字符都需要进行转义, 转义格式为 %HH
URL不允许作为不可行数据输出, 因为没有好的转义方法关闭掉这种攻击,攻击会破坏URL含义。
所有属性应该被引号括起来。
没有括起来的属性很容易被以下字符破坏属性范围, 包括 [space] % * + , - / ; < = > ^ and |.
请注意, 实体转码 是在URL属性值上是无用的。
参考 ESAPI reference implementation ,查阅URL转义和反转义
String safe = ESAPI.encoder().encodeForURL( request.getParameter( "input" ) );
规则#6 使用专门的库清理掉HTML标签
OWASP AntiSamy
import org.owasp.validator.html.*; Policy policy = Policy.getInstance(POLICY_FILE_LOCATION); AntiSamy as = new AntiSamy(); CleanResults cr = as.scan(dirtyInput, policy); MyUserDAO.storeUserProfile(cr.getCleanHTML()); // some custom function
OWASP Java HTML Sanitizer
import org.owasp.html.Sanitizers; import org.owasp.html.PolicyFactory; PolicyFactory sanitizer = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS); String cleanResults = sanitizer.sanitize("<p>Hello, <b>World!</b>");
For more information on OWASP Java HTML Sanitizer policy construction, see http://owasp-java-html-sanitizer.googlecode.com/svn/trunk/distrib/javadoc/org/owasp/html/Sanitizers.html
规则#7 防御DOM Based XSS攻击
参考 OWASP article on DOM based XSS Prevention Cheat Sheet.
额外规则#1 使用HTTPOnly cookie标识
预防所有的XSS攻击是非常困难的,如你所看。为了减轻这个危害造成的后果,
OWASP推荐将会话cookie 和 任何不用脚本访问的cookie设置为 HTTPOnly标识。
For more details on the HTTPOnly cookie flag, including what it does, and how to use it, see the OWASP article on HTTPOnly.
额外规则#2 执行内容安全策略
There is another good complex solution to mitigate the impact of an XSS flaw called Content Security Policy.
XSS防御规则总结
The following snippets of HTML demonstrate how to safely render untrusted data in a variety of different contexts.
Data Type | Context | Code Sample | Defense |
---|---|---|---|
String | HTML Body | <span>UNTRUSTED DATA</span> | |
String | Safe HTML Attributes | <input type="text" name="fname" value="UNTRUSTED DATA"> |
|
String | GET Parameter | <a href="/site/search?value=UNTRUSTED DATA">clickme</a> | |
String | Untrusted URL in a SRC or HREF attribute | <a href="UNTRUSTED URL">clickme</a> <iframe src="UNTRUSTED URL" /> |
|
String | CSS Value | <div style="width: UNTRUSTED DATA;">Selection</div> |
|
String | JavaScript Variable | <script>var currentValue=‘UNTRUSTED DATA‘;</script> <script>someFunction(‘UNTRUSTED DATA‘);</script> |
|
HTML | HTML Body | <div>UNTRUSTED HTML</div> | |
String | DOM XSS | <script>document.write("UNTRUSTED INPUT: " + document.location.hash);<script/> |
Safe HTML Attributes include: align, alink, alt,
bgcolor, border, cellpadding, cellspacing, class, color, cols, colspan,
coords, dir, face, height, hspace, ismap, lang, marginheight,
marginwidth, multiple, nohref, noresize, noshade, nowrap, ref, rel, rev,
rows, rowspan, scrolling, shape, span, summary, tabindex, title,
usemap, valign, value, vlink, vspace, width
输出转码规则总结
The purpose of output encoding (as it relates to Cross Site Scripting) is to convert untrusted input into a safe form where the input is displayed as data to the user without executing as code in the browser. The following charts details a list of critical output encoding methods needed to stop Cross Site Scripting.
Encoding Type | Encoding Mechanism |
---|---|
HTML Entity Encoding | Convert & to & Convert < to < Convert > to > Convert " to " Convert ‘ to ' Convert / to / |
HTML Attribute Encoding | Except for alphanumeric characters, escape all characters with the HTML Entity &#xHH; format, including spaces. (HH = Hex Value) |
URL Encoding | Standard percent encoding, see: http://www.w3schools.com/tags/ref_urlencode.asp. URL encoding should only be used to encode parameter values, not the entire URL or path fragments of a URL. |
JavaScript Encoding | Except for alphanumeric characters, escape all characters with the \uXXXX unicode escaping format (X = Integer). |
CSS Hex Encoding | CSS escaping supports \XX and \XXXXXX. Using a two character escape can cause problems if the next character continues the escape sequence. There are two solutions (a) Add a space after the CSS escape (will be ignored by the CSS parser) (b) use the full amount of CSS escaping possible by zero padding the value. |
Related Articles
XSS Attack Cheat Sheet
The following article describes how to exploit different kinds of XSS Vulnerabilities that this article was created to help you avoid:
- OWASP: XSS Filter Evasion Cheat Sheet - Based on - RSnake‘s: "XSS Cheat Sheet"
A Systematic Analysis of XSS Sanitization in Web Application Frameworks
http://www.cs.berkeley.edu/~prateeks/papers/empirical-webfwks.pdf
Description of XSS Vulnerabilities
- OWASP article on XSS Vulnerabilities
Discussion on the Types of XSS Vulnerabilities
How to Review Code for Cross-site scripting Vulnerabilities
- OWASP Code Review Guide article on Reviewing Code for Cross-site scripting Vulnerabilities
How to Test for Cross-site scripting Vulnerabilities
- OWASP Testing Guide article on Testing for Cross site scripting Vulnerabilities
Authors and Primary Editors
Jeff Williams - jeff.williams[at]owasp.org
Jim Manico - jim[at]owasp.org
Neil Mattatall - neil[at]owasp.org
Other Cheatsheets
Developer Cheat Sheets (Builder)
- Authentication Cheat Sheet
- Choosing and Using Security Questions Cheat Sheet
- Clickjacking Defense Cheat Sheet
- C-Based Toolchain Hardening Cheat Sheet
- Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet
- Cryptographic Storage Cheat Sheet
- DOM based XSS Prevention Cheat Sheet
- Forgot Password Cheat Sheet
- HTML5 Security Cheat Sheet
- Input Validation Cheat Sheet
- JAAS Cheat Sheet
- Logging Cheat Sheet
- .NET Security Cheat Sheet
- Password Storage Cheat Sheet
- Pinning Cheat Sheet
- Query Parameterization Cheat Sheet
- Ruby on Rails Cheatsheet
- REST Security Cheat Sheet
- Session Management Cheat Sheet
- SQL Injection Prevention Cheat Sheet
- Transport Layer Protection Cheat Sheet
- Unvalidated Redirects and Forwards Cheat Sheet
- User Privacy Protection Cheat Sheet
- Web Service Security Cheat Sheet
- XSS (Cross Site Scripting) Prevention Cheat Sheet
Assessment Cheat Sheets (Breaker)
Mobile Cheat Sheets
OpSec Cheat Sheets (Defender)
Draft Cheat Sheets
- OWASP Top Ten Cheat Sheet
- Access Control Cheat Sheet
- Application Security Architecture Cheat Sheet
- Business Logic Security Cheat Sheet
- PHP Security Cheat Sheet
- Secure Coding Cheat Sheet
- Secure SDLC Cheat Sheet
- Threat Modeling Cheat Sheet
- Web Application Security Testing Cheat Sheet
- Grails Secure Code Review Cheat Sheet
- IOS Application Security Testing Cheat Sheet
- Key Management Cheat Sheet
- Insecure Direct Object Reference Prevention Cheat Sheet
- Content Security Policy Cheat Sheet