[转]Web客户端安全性最佳实践(转)

得益于HTML5,Web应用中愈来愈多的逻辑从服务器端迁移到了客户端。于是,前端开发人员也须要更多关注安全性方面的问题。在这篇文章中,我会告诉你如何使你的应用更加安全。我会着重描述一些你可能从未据说过的技术,而不是仅仅告诉你“别忘了对用户提交的页面数据作转义(escape)”。javascript

HTTP?想都别想

固然,我并不想让你经过FTP或者普通的TCP协议来传输你的数据。个人意思是,若是你想让你的用户安全地访问你的网站,你应该使用SSL(HTTPS)来加密你的数据传输。不只要加密登录节点或者关键信息,而是要加密全部的数据。不然当用户经过公用网络访问你的应用时,他看见的内容说不定已经被别人“黑”掉了。这就叫中间人攻击,见下图:php

main-in-the-middle
(译者注:此处引用的原图中笔误,中间人攻击的英文为Man-In-The-Middle Attack)前端

若是你使用SSL,全部的数据在发送以前就会被加密,即便攻击者在网络中截获了数据包,他也没有办法查看或者篡改其中的内容。对于提高应用的安全性,这是目前为止最重要的一步。java

严格传输安全性标记(Strict-Transport-Security)

若是你只想经过SSL来传输你的数据,那么这个HTTP头属性会让你以为很是好用。若是服务器端在响应头中使用了这个标记(你也能够在页面中使用标签,不过这样的话就会存在一个未被加密的请求),那么全部从客户端到服务器端的数据都会被加密。使用方式以下:web

Strict-Transport-Security: max-age=3600; includeSubDomains

其中的includeSubDomains属性是可选的,你可使用它来加密当前域的子域,全部对子域的访问也会被HTTPS加密。而其中的max-age属性能够设置在多长的时间范围内(以秒为单位)须要用SSL对页面数据传输进行加密。不过惋惜的是,目前只有Firefox、Chrome和Opera浏览器支持这个标记。segmentfault

Secure和HttpOnly属性

还有一种方法能够有效加强HTTP和HTTPS访问的安全性,那就是使用Secure和HttpOnly这两个cookie属性。前者能确保cookie的内容只经过SSL链接进行传输;然后者正好相反。若是你以为这二者互相矛盾,没啥用处,那就错了。它们告诉浏览器cookie的内容只能分别经过HTTP(S)协议进行访问,从而避免了被别人轻易窃取,好比JavaScript中的document.cookie.api

经过Content-Security-Policy(CSP)标记来减小跨站脚本攻击(XSS)的危害

若是你以为依靠XSS过滤器可以防范全部可能的XSS攻击,不妨先看一看这篇文章,再好好思考一下。固然,为整个Web应用都配置上完备的防范措施也会存在一些问题,好比,可能拖累整个网站的性能。不过我还有一招。跨域

这招叫作Content-Security-Policy标记。它能让你指定网站上全部脚本和图片等资源的源站点。此外,它还能阻止全部内联(inline)的脚本和样式。即便有人在页面评论或者回帖中嵌入了脚本标签,这些脚本代码也不会被执行。CSP标记通常写在HTTP头中(也能够写在HTML的标签中),写法以下:浏览器

Content-Security-Policy: policy

其中的policy字段表明一系列CSP属性,下面列举一些经常使用的属性:安全

  • script-src – 设置能够接受的JavaScript代码的源站点
  • style-src – 设置能够接受的CSS样式代码的源站点
  • connect-src – 定义浏览器能够经过XHR、WebSocket或者 EventSource访问哪些站点
  • font-src – 设置能够接受的字体文件的源站点
  • frame-src – 定义浏览器能够经过iframe访问哪些站点
  • img-src – 设置能够接受的图片的源站点
  • media-src – 设置能够接受的音频和视频文件的源站点
  • object-src – 设置能够接受的Flash和其它插件的源站点

若是没有设置上述属性,那么浏览器默认会接受来自任何源站点的脚本和数据。不过浏览器的默认属性也能经过default-src属性来设置。其它的属性若是没有设置的话,就会默认采用这个属性中设置的值。此外,还有一个叫作sandbox的属性,它可让浏览器以iframe的形式加载页面。下面是一个CSP头的例子:

Content-Security-Policy: default-src: 'self'; script-src: https://apis.google.com;

在这个例子中,浏览器只会加载源自这个Web应用所在站点的资源(默认源设置为self),以及经过Google API服务器获取的脚本。CSP有不少种灵活的用法,若是使用得当,能够有效提高Web应用的安全性。

CSP的缺点

当你使用CSP的时候,有一点千万要记住:默认状况下,全部的内联JavaScript脚本都不会被执行。例如:

内联的事件监听器:好比

<body onload="main();">

全部的javascript URL:好比

<a href="javascript:doTheClick()"">

之因此这样,是由于浏览器没法区分你的内联脚本和黑客注入的脚本。你须要经过JavaScript的addEventListener或者一些框架中相似的函数来重写上述脚本。某种程度上来看,这也不算一件坏事,它逼你不得不分离逻辑层的代码和展示层的代码,而你原本就应该这么作。此外,CSP默认还会阻止全部eval()风格的代码的执行,包括setInterval/setTimeout中的字符串和相似于new Function(‘return false’)之类的代码。

CSP的可用性

大部分时下流行的浏览器都支持CSP。Firefox、Chrome和Opera(包括手持设备上的)使用标准的CSP头。Safari(包括iOS中的)和安卓上的Chrome使用X-WebKit-CSP头。IE10(仅支持sandbox属性)使用X-Content-Security-Policy头。因此,因为IE的支持(部分支持也是支持),你不只能够着手使用CSP(除非你用的是Google Chrome Frame之类的东西),并且还能在各类实际的浏览器中运行,有效地改善Web应用的安全性。

使用跨域资源共享(Cross Origin Resource Sharing)来代替JSONP

目前因为浏览器同源策略的限制,JSONP常被用于从其它服务器上获取数据。一般的办法是在脚本中写一个回调函数,而后把回调函数的名字写在请求的URL中,像下面这样:

function parseData(data) {
   ...
}


可是这样作会有很大的安全隐患。若是你请求数据的服务器被黑了,那么黑客就能在返回的数据中植入恶意代码,进而窃取用户的隐私信息。由于在浏览器看来,经过这种方法获取的脚本代码和正常的页面代码没什么区别。

正确的作法是使用跨域资源共享。它容许资源提供方在响应头中加入一个特殊的标记,使你能经过XHR来获取、解析并验证数据。这样就能避免恶意代码在你的应用中执行。

这个方法须要在响应头中加入的标记以下:

Access-Control-Allow-Origin: allowed origins

这里能够列举一些能够接受的数据源,以逗号隔开,使用通配符*来接受全部的数据源。

CORS可用性

目前全部主流的浏览器都支持,除了Opera Mini。

固然,更重要的是数据提供方能支持跨域资源共享,不过这就不是开发者能说了算的了。

在iframe中使用sandbox属性

若是你使用iframe加载外部网站的内容,也别忘了它的安全问题。你能够经过iframe的sandbox属性来加强iframe使用的安全性。经过设置sandbox属性,可使得iframe没法随意跳转页面,没法执行外部脚本,没法锁定鼠标,没法弹出新窗口,没法提交表单,等等。此外页面上若干个iframe中加载的全部内容还必须来自惟一的源,也就不能使用localStorage等有悖于同源策略的东西。固然,若是有须要的话,你也能够经过显式的设置来放宽限制,能够设置的属性以下:

  • allow-same-origin –iframe只要各自符合同源规范便可
  • allow-scripts –iframe中能够执行JavaScript脚本
  • allow-forms –iframe中能够提交表单
  • allow-pointer-lock –iframe中能够锁定鼠标
  • allow-popups – iframe中能够弹出新窗口
  • allow-top-navigation – iframe中能够完成页面跳转

可用性

目前iframe的sandbox属性受各类主流浏览器支持,除了Opera Mini之外。

结束语

主要内容就是这些了。但愿读者能经过这篇文章学到一些新技术,能用于从此的项目中,更好的提高Web应用的安全性。得益于HTML5的发展,咱们能够在Web上实现愈来愈丰富的功能。可是咱们也不能掉以轻心,由于网络中攻击和威胁无处不在,在敲第一行代码以前就要好好想想安全性方面的问题。

相关文章
相关标签/搜索