给开发者的终极XSS防护备忘录V1.0AjinAbrahamOWASPXenotixXSS漏洞利用框架作者|opensecurity.in译者:Fooying知道创宇安全研究团队安全研究员|防护备忘录是一份汇总整理自不同组织、研究人员、网站以及我自己经验的用于XSS防护的资料。这份文档通过简单的语言和辩证解释帮助开发者实现正确的XSS防护,并建立一个可以防止XSS漏洞和发起XSS攻击的安全Web应用。它还将讨论各种编程语言提供的用于降低XSS的现有方法及函数。这份文档将会定期更新以包含XSS防护领域中已更新或校正的信息。译者注因为觉得这份文档真心不错,很多人也都推荐,有翻译的价值,于是利用每天下班后的时间做了下翻译,主要靠自己的理解以及谷歌翻译,前后大概是一个礼拜的时间。文档中所有的翻译都争取保留原文的格式,但为了更清楚明了以及语义通顺,一些地方做了一些修饰词及顺序的更改。因为水平有限等原因,文档中的一些翻译可能不是完全到位,欢迎大家指正(可以通过以下联系方式)。联系方式:微博:知乎专栏:邮箱:f00y1n9@gmail.com网址:微信公众号:0xsafe知道创宇安全研究团队简介:什么是XSS?XSS或者说跨站脚本是一种Web应用程序的漏洞,当来自用户的不可信数据被应用程序在没有验证以及反射回浏览器而没有进行编码或转义的情况下进行了处理,导致浏览器引擎执行了代码。XSS类型•反射型XSS•存储型XSS•DOMXSS•突变XSS反射型XSS反射或者非持久型XSS是当不可信的用户输入被服务器在没有任何验证下处理并在没有编码或转义的情况下反射回响应文中,导致代码在浏览器执行的一种XSS漏洞。存储型XSS存储或持久型XSS是当不可信的用户输入被处理并在没有任何验证的情况下保存在文件或数据库,同时该不可信的数据从存储中被获取然后在没有编码或转义的情况下反射回响应文中,导致了永久性的每次存储数据反射回响应文代码就会在浏览器中执行的一种XSS漏洞。DOMXSSDOMXSS是客户端XSS的一种形式,数据来源在DOM中,接收器也在DOM中,而数据流从来没有离开浏览器。它发生在一个不可信的数据在源中被给予并被执行,结果导致修改了DOM在浏览器中的“环境”。DOMXSS攻击发生在不可信数据相对于上下文没有被编码或转义的情况下。突变XSSmXSS或突变XSS是当不可信数据在DOM的innerHTML属性的上下文被处理并通过浏览器发生突变,导致变成一种有效的XSS向量的一种XSS漏洞。在mXSS,一个看起来无害的可以通过客户端或服务端XSS过滤器的用户指定的数据通过浏览器执行引擎发生突变可以反射回一个有效的XSS向量。XSS过滤器不能防止mXSS。为了防止mXSS,应实施有效的CSP,框架应该不被允许,HTML文档应该定义文档类型,强制浏览器遵循标准呈现内容以及执行脚本。XSS防护如果你可以使得一个Web应用程序满足以下规则,XSS可以被减少。1.验证输入并且基于语境和按照正确的顺序转义不可信数据输入验证所有不可信数据应该针对Web应用程序的逻辑在处理和存储前进行验证。浏览器解析顺序浏览器解码顺序解码和解析顺序意味着很多东西。如果对不可信数据的编码或解码以错误的顺序或错误的环境,将再次有机会导致XSS漏洞的发生。编码或者转义对不同的环境要求不同。这些编码的顺序应该取决于应用程序的逻辑。一个典型的不可信数据可以反射在HTML,HTML属性,脚本变量,脚本块,含状态传输的参数,URL、风格等中。不同的转义方法为了确保XSS的防护必须要在不同的环境中实现。顺序和上下文相关转义1.HTML中的字符串对HTML中不可信字符串进行HTML转义。Example:1.h1Welcomehtml_escape(untrustedstring)/html符号编码&&<>"``''//2.HTML属性中的字符串对于HTML属性中不可信字符串进行HTML转义,并且总是为你的属性加上引号,无论是(‘或“),不要使用反引号(`)。Example:1.imgsrc=xalt=html_escape(untrustedstring)除了字母数字字符,用格式(或者命名实体,如果可用)转义所有ASCII值小于256的字符以防止开关的值伸出属性。恰当的为属性加上引号可以只被对应的引号转义。不带引号的属性可以被分解为许多个字符,包括和。3.事件句柄属性和JavaScript中的字符串对于事件句柄属性中的不可信字符串,先进行JavaScript转义,然后执行HTML转义,因为浏览器在执行JavaScript字符串解码前执行HTML属性解码。对于JavaScript中的非可信数据,进行JavaScript字符串转义并且总是将属性加上引号,无论是(‘或“),但不要使用反引号(`)。Example:1.//InthecontextofEventHandler2.imgsrc=xonload=jsFunction('html_escape(javascript_string_escape(untrustedstring))')3.//InthecontextofJavaScript4.scripttype=text/javascript5.varabc='javascript_string_escape(untrustedstring)';6./script除了字母数字字符,以格式转义小于256的所有字符,以防开关的值伸到脚本中或另一个属性。不要使用类似的转义符号,因为引号符号可能被HTML属性解析器在第一次运行被匹配。这些转义字符也容易受到”转义已转义”的攻击,攻击者发送和漏洞代码转为使得可以成为引号。如果事件句柄属性被正确引号,需要通过相应的引号来闭合。不带引号的属性可以被分割为许多字符,包括另外,一个闭合标签可以闭合脚本块,即使它是一个带引号的字符串。需要注意的是,HTML解析器在JavaScript解析器之前运行。4.HTML属性中的URL路径对HTML属性中的URL路径进行转义而不是完整的URL。总是为属性加上引号,无论是(‘或“),但不要使用反引号(`)。绝不允许或包含格式像或或者他们的组合(如)。和Example:1.ahref==url_escape(untrustedstring)l/a2.imgsrc=/url_escape(untrustedurlpathstring)3.formaction=/?i=url_escape(untrustedstring)method=GET/form除了字母数字字符,用格式转义所有ASCII值小于256的字符。如果或属性被正确的引号起来,突破需要对应的引号。未被引号属性可以使用许多字符进行突破,包括和。请注意,这种情况下,实体编码是无用的。5.HTML风格属性和CSS中的字符串对HTML样式属性内的不可信字符串先做CSS字符串转义,然后进行HTML转义,因为解析器的解析顺序是先HTML解析器然后再CSS解析器。总是给你的属性加上引号,如本例子中的风格属性加上(“),CSS字符串加上(‘),不要使用反引号(`)。为在CSS中的不可信字符串做CSS字符串转义。也要确保不可信字符串在引号(‘或“)之间,不要使用反引号(`)。也不要允许expression以及它的复杂组合,如(expre/**/ssion)。Example:除了字母数字字符,用格式转义所有ASCII值小于256的字符。不要使用任何类似的转义符号,因为引号符号可能被HTML属性解析器在第一次运行被匹配。这些转义字符也容易受到”转义已转义”的攻击,攻击者发送和漏洞代码转为使得可以成为引1.//InthecontextofHTMLstyleAttribute2.pstylefontfamily:'html_escape(css_string_escape(unntrustedstring))'3.HelloWorld!4./p5.//InthecontextofCSS6.style7.#css_string_escape(untrustedstring)8.{9.text-align:center;10.color:red;11.}12./style号。如果属性被正确引号,需要通过相应的引号来闭合。不带引号的属性可以被分割为许多字符,包括。同时,标签会关闭风格块,即使是在一个被引号的字符串内。请注意,HTML解析器在CSS解析器前运行。6.JavaScript中的HTML对于JavaScript字符串中不可信的HTML,先执行HTML转义,然后执行JavaScript字符串转义,保持这个顺序。Example:9.divid=disp/div/body2.始终遵循白名单优于黑名单的做法创建个Web应用程序应该允许的来自用户的标签和属性的白名单。黑名单可以很容易的被绕过。3.使用UTF-8为默认的字符编码以及设置content为text/html和1.script2.functionxyz()3.{4.varelm=document.getElementById(disp);5.elm.innerHTML=strongjavascript_string_escape(html_escape(untrustedstring))/strong;6.}7./script8.bodyonload=xyz()在HTML文档,你可以指定meta标签,如4.不要将用户可以控制的文本放在meta标签前。通过使用不同的字符集注射可以导致XSS。在meta之前,可以通过注射覆盖默认的字符集,并允许宽字节创建一个有效的XSS向量。Demo使用!DOCTYPEhtmlDOCTYPE(DTDorDocumentTypeDeclaration,译者注:文档类型声明)告诉你的浏览器遵循标准进行HTML,CSS的渲染以及如何执行脚本。总是在之前使用。6.使用推荐的HTTP响应头进行XSS防护HTTP响应头描述X-XSS-Protection:1;mode=block该响应头会开启浏览器的防XSS过滤器。X-Frame-Options:deny该响应头会禁止页面被加载到框架。X-Content-Type-Options:nosniff该响应头会阻止浏览器做MIMEtype(译者.注:MultipurposeInternetMailExtensions,代表互联网媒体类型)嗅探。.Content-Security-Policy:default-src'self'该响应头是防止XSS最有效的解决方案之一。它允许我们定义从URLS或内容中加载和执行对象的策略Set-Cookie:key=value;HttpOnlySet-Cookie响应头通过HttpOnly标签的设置将限制JavaScript访问你的Cookie。Content-Type:type/subtype;charset=utf-8始终设置响应的内容类型和字符集.例如:返回json格式应该使用application/json,纯文本使用text/plain,HTML使用text/html等等,以及设置字符集为utf-8。7.防止CRLF注入/HTTP响应拆分对所有用户提供的数据在它们传递通过HTTP头前进行正确的清洁和编码。CRLF注入可以摧毁和绕过CSP