不可忽视的前端安全问题——XSS攻击

XSS是什么

XSS是跨站脚本攻击(Cross-Site Scripting)的简称。javascript

XSS是一种注入脚本式攻击,攻击者利用如提交表单、发布评论等方式将事先准备好的恶意脚本注入到那些良性可信的网站中,当其余用户进入该网站后,脚本就在用户不知情的状况下偷偷地执行了,这样的脚本可能会窃取用户的信息、修改页面内容、或者伪造用户执行其余操做等等,后果不可估量。php

XSS攻击一般会发生在如下状况下:
html

  • 向一个web app中输入含有一些不良代码的内容,一般是一段含有http请求的代码
  • 这些内容包含在发给其余用户的动态内容之中,并且这些内容尚未通过校验

发送到Web浏览器的恶意内容一般采用JavaScript代码片断的形式,但也可能包括HTML,Flash或浏览器可能执行的任何其余类型的代码。 基于XSS的攻击方式几乎是无限的。可是它们一般的方式是:前端

  • 向攻击者发送包括诸如cookie或其余会话信息的私有数据
  • 攻击者篡改页面的内容
  • 在用户的机器上,以含有漏洞的网站为幌子,执行其余恶意操做

OWASP(Open Web Application Security Project)最新公布的2017 10项最严重的 Web 应用程序安全风险中,XSS榜上有名。
java


而事实上,XSS在每次的TOP10评比中都会出现……
angularjs


XSS实例

想知道XSS是如何形成攻击的?能够看这个下面的文章,它介绍了一个XSS漏洞——XSS跨站脚本攻击过程最简单演示 - CSDN博客 案例中攻击者利用XSS能够获取用户的隐私信息。golang

XSS攻击的分类

通常会把XSS分为两类——存储型XSS(Stored XSS)和反射型XSS(Reflected XSS)web

不过还有一种鲜为人知的类型——DOM-based XSS。数据库


存储型XSS是指那些将恶意脚本永久的保存在目标服务器上的攻击方式,如存储在数据库、消息论坛、访问日志、评论内容扥等。express

反射型XSS是当用户点击一个恶意连接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。Web服务器将注入脚本,好比一个错误信息,搜索结果等 返回到用户的浏览器上。浏览器会执行这段脚本,由于,它认为这个响应来自可信任的服务器。一个危险的XSS案例--轻松拿到登陆用户的cookie - CSDN博客,这个例子中,若是有人诱导你点击了上面文章中写到的连接,那么你在站酷网站中的隐私信息就发送到了其余服务器中了。


DOM-Based型XSS是指攻击者利用原生JavaScript代码篡改客户端的DOM结构,致使用户操做执行了“意外”的动做。

关于DOM-Based型XSS能够看下面的例子

下面是一段网站的代码,它提供一个下拉框让你来选择语言,并且还根据你URL上的default参数来进行默认语言的推荐。

Select your language:

<select><script>

document.write("<OPTION value=1>"+document.location.href.substring(document.location.href.indexOf("default=")+8)+"</OPTION>");

document.write("<OPTION value=2>English</OPTION>");

</script></select>
…复制代码

一般状况下,这个页面的地址会是下面的样子:

http://www.some.site/page.html?default=French复制代码

而DOM-Based型XSS会利用这个页面DOM结构的漏洞,向受害者发送下面的连接

http://www.some.site/page.html?default=<script>alert(document.cookie)</script>复制代码

当受害者点开这个连接时,就会将用户的cookie所有alert出来了。


XSS的防范原则

关于XSS攻击的防范,我在OWASP上给出防范方法进行了精简,若是你有兴趣的话,能够去看详细内容

原则0——永远不要把不受信任的数据插入到本来容许JavaScript能够放置的地方

就像下面的代码中所示的那样:

<script>...永远不要把不受信任的数据放在这...</script>   直接放在script标签内
 
 <!--...永远不要把不受信任的数据放在这...-->             放在HTML注释内
 
 <div ...永远不要把不受信任的数据放在这...=test />       作为一个属性名
 
 <永远不要把不受信任的数据放在这... href="/test" />   作为一个标签名
 
 <style>...永远不要把不受信任的数据放在这...</style>   直接放在style标签内复制代码

原则1——在向元素中插入不受信任的HTML代码以前必定要进行转义

就像下面的代码中所示的那样:

<body>...将不受信任的数据转义后再放在这...</body>
 
 <div>...将不受信任的数据转义后再放在这...</div>
 
 any other normal HTML elements复制代码

经常使用的转义规则以下:

& --> &amp;
 < --> &lt;
 > --> &gt;
 " --> &quot; ' --> &#x27; / --> &#x2F;复制代码

原则2——在向元素的属性插入不受信任的HTML代码以前必定要进行转义

看下面的代码:

<div attr=...将不受信任的数据转义后再放在这...>content</div>  
在没有加引号的属性值内
 
 <div attr='...将不受信任的数据转义后再放在这...'>content</div>
在加了单引号的属性值内

<div attr="...将不受信任的数据转义后再放在这...">content</div>
在加了双引号的属性值内复制代码

原则3——在用不受信任的数据向JavaScript代码赋值前,必定要进行转义

看下面的代码:

<script>alert('...将不受信任的数据转义后再放在这...')</script>     
在一个字符串以内
 
 <script>x='...将不受信任的数据转义后再放在这...'</script> 
在表达式的一侧
 
 <div onmouseover="x='...将不受信任的数据转义后再放在这...'"</div>  
在事件处理函数内复制代码

须要注意的是,有一些JavaScript函数永远没法安全的使用不受信任的数据做为输入,好比下面的代码:

<script>
 window.setInterval('即便你作了转义,可是仍然可能被XSS攻击');
 </script>复制代码


原则3.1——在HTML的上下文中对JSON值进行转义,并用JSON.parse()方法来读取值

必定要确保http response中的头部信息的content-type为application/json,而不是text/html,由于那样的话,极可能会被人利用进行XSS攻击。


一个坏的案例:

HTTP/1.1 200
   Date: Wed, 06 Feb 2013 10:28:54 GMT
   Server: Microsoft-IIS/7.5....
   Content-Type: text/html; charset=utf-8 <-- bad
   ....
   Content-Length: 373
   Keep-Alive: timeout=5, max=100
   Connection: Keep-Alive
   {"Message":"No HTTP resource was found that matches the request URI 'dev.net.ie/api/pay/.html?HouseNumber=9&AddressLine =The+Gardens<script>alert(1)</script>&AddressLine2=foxlodge+woods&TownName=Meath'.","MessageDetail":"No type was found that matches the controller named 'pay'."}   <-- 这里script标签有可能会被执行复制代码

一个好的案例:

HTTP/1.1 200
   Date: Wed, 06 Feb 2013 10:28:54 GMT
   Server: Microsoft-IIS/7.5....
   Content-Type: application/json; charset=utf-8 <--good
   .....
   .....复制代码


原则4——在将不受信任的数据做为CSS属性插入到文档以前必定要进行转义

看下面的代码

<style>selector { property : ...将不受信任的数据转义后再放在这...; } </style> 
属性值

 <style>selector { property : "...将不受信任的数据转义后再放在这..."; } </style>
属性值

 <span style="property : ...将不受信任的数据转义后再放在这...">text</span> 
属性值复制代码

须要注意的是,仍是有一些CSS属性值对于“不受信任的”数据是没法确保万无一失的——即便作了转义,以下面的两个CSS属性:

{ background-url : "javascript:alert(1)"; }  
 { text-size: "expression(alert('XSS'))"; }   // only in IE复制代码

你应该确保全部CSS属性值引入的外部连接是由“http”开头的,而不是“javascript”开头的。


原则5——在向HTML的URL参数插入将不受信任的数据前,必定要将进行转义

看下面的代码

<a href="http://www.somesite.com?test=...将不受信任的数据转义后再放在这...">link</a >复制代码


加分原则1——对于cookie使用httpOnly标识

使用httpOnly标识后的cookie JavaScript是没法获取的,又因为cookie是基于同源原则,因此必定程度上会防范那些利用客户cookie的XSS攻击。


加分原则2——在http header中使用Content Security Policy

利用http header中的属性值Content-Security-Policy来防范XSS。HTTP 响应头 Content-Security-Policy 容许站点管理者在指定的页面控制用户代理的资源。除了少数例外,这条政策将极大地指定服务源 以及脚本端点。


加分原则3——使用自动转义模板系统

许多Web应用程序框架提供了自动的上下文转义功能,如AngularJS严格的上下文转义Go模板。 尽量使用这些技术。


加分原则4——在http header中使用X-XXS-Protection

HTTP X-XSS-Protection 响应头是Internet Explorer,Chrome和Safari的一个功能,当检测到跨站脚本攻击 (XSS)时,浏览器将中止加载页面。虽然这些保护在现代浏览器中基本上是没必要要的,当网站实施一个强大的Content-Security-Policy来禁用内联的JavaScript ('unsafe-inline')时, 他们仍然能够为尚不支持 CSP 的旧版浏览器的用户提供保护。



总结

XSS攻击的后果是不可估量的,而每每他又是容易被人忽视的。结合上面提到的几点,检查一下本身的Web App是否有上面的漏洞。

若是你坚持将全文都看完,你必定深爱着前端技术,那我以为你有必要关注一下个人公众号——较真的前端,在那里会有更多的技术分享和前端干货等着你。


参考文章:
8大前端安全问题(上) - ThoughtWorks洞见 
Cross-site Scripting (XSS) 
XSS (Cross Site Scripting) Prevention Cheat Sheet
相关文章
相关标签/搜索