XSS的类型:反射型XSS、存储型XSS、DOM型XSS
跨站点脚本防范的基本原则:
- 一切的输入/输出都是有害的,不要信任任何输入/输出数据。
- 所有传递过程都不能保障无侵入,执行前、存储前、显示前都要进行“数据清洁”。
- 所有的数据校验、处理工作要在前端和服务器端两次进行。
- 目前所有的XSS通过com.keegoo.core.util.XSSUtil来过滤。
DOM-based XSS的防范当操作页面中DOM对象的时候,要对其输入的参数进行处理,防止XSS的注入。可采用escape、encodeURI、encodeURIComponent或自定义方法进行处理。示例:
Window.location=encodeURI(”http://www.dhgate.com”);
对输入/输出进行Encode 将输入/输出进行转义成HTML实体编码(ISO 8859-1 Latin1)或其他编码,使得其在浏览器中不可自动执行。
不要在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
<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
HttpOnly
(1) 浏览器禁止页面的JavaScript访问带有HttpOnly属性的Cookies。
(2) 添加HttpOnly的过程简单,效果明显,有如四两拨千斤。已成为一种“标准”做法。
(3) 但在部署时需注意,若业务非常复杂,则需要在所有Set-Cookies的地方,给关键的Cookies都加上HttpOnly,漏掉任一地方,都可能使得方案失效。
(4) Apache支持一个Header的TRACE,TRACE一般用于调试,它会将请求头作为HTTP Response Body返回。漏洞也修复。
输入检查
(1) 输入的检查的逻辑,必须放在服务器端代码中实现,若只在客户端使用JavaScript中设置输入检查,是很容易被攻击者绕过的。
(2) 这种输入检查的方式,可以称为“XSS Filter”
输出检查
(1) 安全的编码函数
- 要求使用JavascriptEncode的变量输入一定要在引号内
如var y = ‘”’+escapeJavascript($evil)+’”’
- 若开发者没有此习惯,则只能使用改一个更加严格的JavascriptEncode函数来保证安全--除了数字、字母外的所有字符,都是用十六进制“\xHH”的方式进行编码。
- 需要注意的是,编码后的数据长度可能会发生改变,从而影响某些功能。再写代码市需要注意这个细节,以免产生不必要的bug。
(2) 只需要一种编码吗
- XSS攻击主要发生在MVC架构中的View层。大部分的XSS漏洞可以在模版系统中解决.
- 需要区分输出变量的语境,并非在模版引擎中使用auto-escape就万事大吉了(比如:对于浏览器来说,htmlparser会优先于JavaScript Parser执行,所以解析的过程是HtmlEncode的字符先被解码,然后执行JavaScript事件)
注释:
escape()和unescape()是一对编码解码函数,一般用于URL中非ASCII字符的编码和解码!如:escape("&")返回%26,unescape("%26")返回&,都用十六进制编码!
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写
正确的防御XSS
(1) XSS本质是一种”HTML注入”,用户的数据本当成了HTML代码中的一部分来执行,从而混淆了原本的语义,产生了新的语义。
(2) 如果网站使用了MVC架构,那么XSS就发生在View层—在应用拼接变量到HTML页面时产生。
(3) 在用户提交数据处进行输入检测的方案,其实并不是在真正发生攻击的地方做防御。
(4) 在HTML标签中输出
- 在所有标签中输出的变量,如果未做任何处理,都能导致直接产生XSS。
- 防御方法是对变量使用HtmlEncode(HtmlEncode:是将html源文件中不容许出现的字符进行编码,通常是编码以下字符:"<"、">"、"&"、"""、"'"等;)
(5) 在HTML属性中输出
- OWASP ESAPI中推荐了一种更为严格的HtmlEncode—除了字母、数字外,其他所有的特殊字符都被编码成HTMLEntities
String safe = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));
这种严格的编码方式,可以保证不会出现任何的安全问题
(6) 在<script>标签中输出
- 在<script>标签中输出时,首先应该确保输出的变量在引号中
- 攻击者需要先闭合引号才能实施XSS攻击
- 防御时使用JavascriptEncode
(7) 在事件中输出
- 与<script>标签类似
- 防御时使用JavascriptEncode
(8) 在CSS中输出
- 尽可能禁止用户可控制的变量在“<style>标签”、“HTML标签的style属性”以及“CSS文件”中输出
- 如果一定有这样的需求,推荐使用OWASP ESAPI中的encodeForCSS()函数。
- 其实现原理类似于ESAPI.encoder().encodeForJavaScript()函数,除了字母、数字外的所有字符被编码成十六进制形式“\uHH”
防御DOM Based XSS
(1) 事实上,DOM Based XSS是从JavaScript中输出数据到HTMNL页面里
(2) 从JavaScript输出到HTML页面,也相当于一次XSS输出的过程,需要分语境使用不同的编码函数。
Document.write输出到HTML页面时,
如果是输出到事件或脚本,则要再做一次javascriptEncode,
如果是输出到HTML内容或者属性,则要做一次HtmlEncode
(3) 会触发DOM Based XSS的地方有很多,以下几个地方是JavaScript输出到HTML页面的必经之路
- document.write()
- document.writeln()
- xxx.innerHTML =
- xxx.outerHTML =
- innerHTML.replace
- document.attachEvent()
- window.attachEvent()
- document.location.replace()
- document.location.assign()
- ……
需要重点关注这几个地方的参数是否可以被用户控制
(4) 除了服务端直接输出变量到JavaScript外,还有以下一个地方可能会成为DOM Based XSS的输入点,也需要重点关注
- 页面中所有的inputs框
- window.location(href、hash等)
- window.name
- document.referrer
- document.cookies
- localstorage
- XML HttpRequest返回的数据
(5) 安全研究者Stefano Di Paola设立了一个DOM Based XSS的cheatsheet,地址如下:http://code.google.com/p/domxsswiki
换个角度看XSS风险
(1) 存储型XSS可能会绕过些检查工具(如IE8的XSS Filter,firefox的Noscript Extension都会检查地址栏中的地址是否包含XSS脚本)
(2) 从攻击过程来说,存储型XSS 风险颇高
(3) 从风险角度看,互动的页面是可能发起XSS Worm攻击的地方
(4) 从业务风险的角度来重新定位每个XSS漏洞,具有更重要的意义。(比如:在网站首页发生的XSS攻击要比网站的合作伙伴页面的XSS攻击要严重的多)