web安全机制问题详解之一:XSS

web安全是前端开发者们须要关注和掌握的必要内容。在写该记录以前,我也老是对安全策略这方面点到为止;可是在真正了解以后才发现,页面能安全活到如今也算是老天和后台、运维同事的关照了。😂javascript

本次记录主要有三点:XSS、CSRF、CSP、请求劫持和https。html

这一篇,会详细记录xss的攻击和防护。另外两点会分为两篇记录文:详解二详解详解四前端

1. XSS 漏洞的发生和修复

XSS(cross-site scripting)跨站脚本攻击是指页面被注入恶意代码。java

例1:根据请求接口URL参数决定页面展现内容时:web

<input type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>
<div>
  您搜索的关键词是:<%= getParameter("keyword") %>
</div>复制代码

getParameter('keyword')是http请求的函数ajax

url:http://xxx/search?keyword="><script>alert('xss');</script>"数据库

参数keyword会被从新拼接到HTML中:编程

<input type="text" value=""><script>alert('XSS');</script>"> <button>搜索</button><div> 您搜索的关键词是:"><script>alert('XSS');</script> </div>复制代码

恶意代码将被执行。后端

面对这种状况如何防范?浏览器

这里的缘由是,浏览器把用户的输入当成脚本执行了,那么将这段内容转成文本就行。

<input type="text" value="<%= escapeHTML(getParameter("keyword")) %>">
<button>搜索</button>
<div>
  您搜索的关键词是:<%= escapeHTML(getParameter("keyword")) %>
</div>复制代码

excapeHTML()按照如下规则进行转译:

|字符|转义后的字符| |-|-| |&|&amp;| |<|&lt;| |>|&gt;| |"|&quot;| |'|&#x27;| |/|&#x2F;|

经转译后,最终浏览器接收到的响应为:

<input type="text" value="&quot;&gt;&lt;script&gt;alert(&#x27;XSS&#x27;);&lt;&#x2F;script&gt;">
<button>搜索</button>
<div>
  您搜索的关键词是:&quot;&gt;&lt;script&gt;alert(&#x27;XSS&#x27;);&lt;&#x2F;script&gt;
</div>复制代码

例2:a标签的href属性

<a href="<%= escapeHTML(getParameter("redirect_to")) %>">跳转...</a>复制代码

getParameter('redirect_to')为URL http://xxx/?redirect_to=javascript:alert('XSS')

即便作了转译,javascript:仍然是正确的href属性值,包括在javascript:前面加空格%20,也依然会跳过HTML转译检查。

解决办法:白名单过滤,禁止'javascript:'连接、非法schema等。

例3:把数据经过JSON的方式内联到HTML中

<script>
var initData = <%= data.toJSON() %>
</script>复制代码

这时不能使用escapeHTML(),由于转译"后,JSON格式会被破坏。

可是内联JSON也有不安全的地方:

  • 当 JSON 中包含 U+2028U+2029 这两个字符时,不能做为 JavaScript 的字面量使用,不然会抛出语法错误。
  • 当 JSON 中包含字符串 </script> 时,当前的 script 标签将会被闭合,后面的字符串内容浏览器会按照 HTML 进行解析;经过增长下一个 <script> 标签等方法就能够完成注入。

所以,须要escapeEmbedJSON()函数,对内联JSON进行转义:

|字符|转义后的字符| |-|-| |U+2028|\u2028| |U+2029|\u2029| |<|\u003c|

2. 漏洞总结

  • 恶意内容以<script>标签形式注入HTML内嵌的文本中
  • 内联的javascript中,拼接的数据超过escapeHTML()的限制
  • 标签属性中,恶意内容若包含引号,能够注入其余属性或标签
  • 标签的href、src属性中,包含javascript:等可执行代码
  • 在onload, onerror, onclick等事件中,注入恶意代码

3. XSS攻击的分类

利用恶意脚本攻击,攻击者能够获取用户的敏感信息如Cookie、SessionID等。

用户输入行为,如下内容都不可信:

  • 来自用户的 UGC(user generated content) 信息
  • 来自第三方的连接
  • URL 参数
  • POST 参数
  • Referer (可能来自不可信的来源)
  • Cookie (可能来自其余子域注入)

根据攻击来源,能够分为存储型、反射型和DOM型三类。

|类型|存储区|插入点|

|存储型 XSS|后端数据库|HTML| |反射型 XSS|URL|HTML| |DOM 型 XSS|后端数据库/前端存储/URL|前端 JavaScript

存储型XSS攻击步骤:

1. 攻击者将恶意代码提交到目标网站数据库

2. 用户打开目标网站时,网站服务端将恶意代码从数据库提出,拼接到HTML中返回给浏览器

3. 用户浏览器接收到响应后解析执行,恶意代码也被执行

4. 恶意代码窃取用户数据并发送到攻击者网站,或者冒充用户行为,调用目标网站接口执行恶意操做

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

反射型XSS攻击步骤:

1. 攻击者构造出包含恶意代码的URL

2. 用户打开含恶意代码的URL,网站服务端取出恶意代码并拼接到HTML返回浏览器

3. 浏览器解析执行,窃取用户数据或冒充用户行为

与存储型的区别,反射型的恶意代码存储在URL,存储型的存储在数据库。反射型XSS漏洞常见于经过URL传参的功能,如网站搜索、跳转等。

因为须要用户主动打开,因此会有多种诱导用户点击的手段。POST的内容也能够触发反射型XSS,只不过须要构造表单提交页面引导用户点击,因此少见。

DOM型攻击步骤:

1. 攻击者构造出包含恶意代码的URL

2. 用户打开该URL

3. 浏览器接收到响应后解析执行,前端JS取出URL中的恶意代码并执行。

4. 恶意代码窃取用户数据并发送到攻击者网站,或者冒充用户行为,调用目标网站接口执行恶意操做

DOM型XSS属于前端Javascript自身的安全漏洞,而前两种属于服务端的安全漏洞。

4. XSS攻击的预防

据上所属,XSS攻击主要有两大要素:

1. 攻击者提交恶意代码

2. 浏览器执行恶意代码

从一开始的案列中得知,最简单的是对用户输入文本的转义。可是也知道转义存在弊端。

除此转义以外,也能够对一些必要的输入作检查,如电话号码、数字、URL、邮件地址等。

预防存储型和反射型XSS

存储型和反射型都是在服务端取出恶意代码后,插入html的,被浏览器执行。因此常见的预防方式有两种:改为纯前端渲染,把代码和数据分隔开;对html作充分转义。

纯前端渲染:浏览器先加载静态页面(不包含任何业务相关的数据),再执行javascript,经过ajax加载业务数据,调用DOM API更新到页面上。纯前端渲染中,浏览器会明确文本(.innerText),属性(.setAttribute),仍是样式(.style)等等。但仍须注意避免DOM型XSS(请参考下文‘预防DOM型XSS攻击’)。

不少内部、管理系统中,适合使用纯前端渲染;但对于性能要求高的,或有SEO需求的页面,拼接HTML的问题仍存在。

转义HTML:除了上面说到的excapeHTML()等方法外,还能够直接使用模板引擎,如ejs、doT.js、FreeMarker等,一般就是把& < > " ' /这些转义掉,确实能起到必定的转义做用,但并不完善。因此还能够结合后台编程语言,找到合适的转义库。如JAVA工程里,经常使用的转义库org.owasp.encode,不一样上下文要使用相应的转移规则。

预防DOM型XSS攻击

DOM型XSS攻击就与前段javascript代码自己是否严谨有关。

尽可能避免使用.innerHTML、outerHTML、document.write(),而换成.textContent、.setAttribute()等。

若是用Vue/React技术栈,而且不使用v-html/dangerouslySetInnerHTML功能,就在前段render阶段避免innerHTL、outerHTML的XSS隐患。

DOM 中的内联事件监听器,如 locationonclickonerroronloadonmouseover 等,<a> 标签的 href 属性,JavaScript 的 eval()setTimeout()setInterval() 等,都能把字符串做为代码运行。若是不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。

其余XSS预防措施

Content Security Policy,俗称csp,在http请求时可在请求头中显示。做用:

  • 禁止加载规定域之外的代码
  • 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域
  • 禁止内联脚本执行
  • 禁止未受权脚本执行
  • 合理上报XSS问题,利于尽快修复

输入内容长度控制。

cookie的http-only限制:cookie只容许同域http请求携带,不容许读取和修改。

验证码:图片验证码、短信验证码等等。

5. XSS检测

通用XSS攻击字符串手动检测。

扫描工具自动检测,如Arachni、Mozilla HTTP Observatory、w3af等。

6. XSS攻击的总结

虽然很难经过技术手段彻底避免XSS,但能够尽可能减小漏洞的发生:

  • 利用模板引擎 开启模板引擎自带的 HTML 转义功能。例如: 在 ejs 中,尽可能使用 <%= data %> 而不是 <%- data %>; 在 doT.js 中,尽可能使用 {{! data } 而不是 {{= data }; 在 FreeMarker 中,确保引擎版本高于 2.3.24,而且选择正确的 freemarker.core.OutputFormat
  • 避免内联事件 尽可能不要使用 onLoad="onload('{{data}}')"onClick="go('{{action}}')" 这种拼接内联事件的写法。在 JavaScript 中经过 .addEventlistener() 事件绑定会更安全。
  • 避免拼接 HTML 前端采用拼接 HTML 的方法比较危险,若是框架容许,使用 createElementsetAttribute 之类的方法实现。或者采用比较成熟的渲染框架,如 Vue/React 等。
  • 时刻保持警戒 在插入位置为 DOM 属性、连接等位置时,要打起精神,严加防范。
  • 增长攻击难度,下降攻击后果 经过 CSP、输入长度配置、接口安全措施等方法,增长攻击的难度,下降攻击的后果。
  • 主动检测和发现 可以使用 XSS 攻击字符串和自动扫描工具寻找潜在的 XSS 漏洞。
相关文章
相关标签/搜索