web安全防范知识科普
我们日常访问网页,首先要通过浏览器,而浏览器实际上就是一个客户端软件,如果在这个软件层面上浏览器没有具备安全功能,那么我们可能就会因为访问了某个网页,导致我们的计算机被感染。
但实际上,现在我们基本不会因为单纯浏览网页而导致电脑感染病毒(不下载文件的情况下),因为浏览器本身是具备一些安全功能的,在了解web安全知识前,我们要先了解下一些主要的浏览器安全功能。
浏览器安全
1. 同源政策
同源政策(Same Origin Policy)是浏览器安全的基石,如果缺少同源政策,那么浏览器的正常功能可能都会受到影响。
1.1 含义
1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页同源
。所谓"同源"指的是"三个相同"。
- 协议相同
- 域名相同
- 端口相同
举例来说,http://www.example.com/dir/page.html
这个网址,协议是http://
,域名是www.example.com
,端口是80
(默认端口可以省略)。它的同源情况如下:
- http://www.example.com/dir2/other.html:同源
- http://example.com/dir/other.html:不同源(域名不同)
- http://v2.www.example.com/dir/other.html:不同源(域名不同)
- http://www.example.com:81/dir/other.html:不同源(端口不同)
1.2 目的
为什么需要同源政策呢?
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A 网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,“同源政策”是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
1.3 限制范围
浏览器的同源政策,限制了来自不同源的document
或脚本,对当前document
读取或设置某些属性。
简单来说,如果非同源,共有三种行为受到限制:
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得。(通过frame)
- AJAX 请求不能发送。
浏览器沙箱
如果网页代码直接运行在我们电脑的系统进程中,那么网页中的恶意代码就有可能会利用浏览器漏洞执行任意代码对我们的电脑进行攻击。
为了对抗“挂马”、“内存攻击”等恶意行为,浏览器发展出了多进程架构和 Sandbox(沙箱),从安全性上有了很大的提高。
Google Chrome 是第一个采取多进程架构的浏览器。Google Chrome 的主要进程分为:浏览器进程、渲染进程、插件进程、扩展进程。插件进程如 flash、java、pdf 等与浏览器进程严格隔离,因此不会互相影响。
渲染引擎由 Sandbox 隔离,网页代码要与浏览器内核进程通信、与操作系统通信都需要通过 IPC channel(进程间的通信管道),在其中会进行一些安全检查。
Sandbox 就是资源隔离模块。Sandbox 的设计目的一般是为了让不可信任的代码运行在一定环境中,限制不可信任的代码访问隔离区之外的资源、如果一定要跨越 Sandbox 边界产生数据交换,则只能通过指定的数据通道,比如经过封装的 API 来完成,在这些 API 中会严格检查请求的合法性。
而对浏览器来说,采用 Sandbox 技术,无疑可以让不受信任的网页代码、JavaScript 代码运行在一个受到限制的环境中,从而保护本地桌面系统的安全。
(Google Chrome 的架构)
上图是 Google Chrome 的架构,其中browser kernel
只负责画画UI,网络连接,与文件系统交互等基本工作,而rendering engine
则是负责解析HTML,JavaScript 等工作。他们之间的交流需要通过指定的通道。
但是浏览器安全是一个整体,在现今的浏览器中,虽然有多进程架构和 Sandbox 的保护,但是浏览器所加载的一些第三方插件却往往不受 Sandbox 管辖,如 Flash、Java、PDF 等第三方软件并没有走 Sandbox,他们的安全完全依赖自身的实现。所以这些第三方插件近年来都成为浏览器攻击的热点。
接下来开始介绍 web 脚本安全领域常见的攻击方式和防范手段。
跨站脚本攻击(XSS)
跨站脚本攻击,英文全称是 Cross Site Script,本来缩写是 CSS,但是为了和层叠样式表(Cascading Style Sheet,CSS)有所区别,所以在安全领域叫做XSS
。
XSS 攻击,通常指黑客在发现一个网页的 XSS 漏洞后通过“HTML注入”的方式插入恶意的脚本,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如,盗取用户Cookie、破坏页面结构、重定向到其它网站等。
理论上,网页上所有可输入的地方没有对输入数据进行处理的话,都可能存在XSS漏洞,漏洞的危害取决于攻击代码的威力。
XSS 根据效果的不同可以分成如下几类。
第一种类型:反射型 XSS
反射型 XSS 只是简单地把用户输入数据“反射”给浏览器。也就是,黑客往往需要诱使用户点击一个恶意链接,才能攻击成功。
举个例子:
假设我们在访问某个网页的时候,在URL后面加上参数,服务器会根据请求的参数值构造不同的 HTML 返回。
如http://www.yangzicong.com/xss/reflectedXSS?param=value...
上例中的 value 可能出现在返回的 HTML(能是JS,HTML某元素的内容或者属性)中, 如果将 value 改成可以在浏览器中被解释执行的东西,就形成了反射型XSS。
这时别人可能修改这个value值,然后诱使你打开这个链接(例如,将这个恶意的URL发送给你),当这个链接被打开时,特有的恶意代码参数被 HTML 解析,执行。它的特点是非持久化,必须用户点击带有特定参数的链接才能引起。
例如修改成?param=<script>alert('???')</script>
,当点击这个链接时,自然就会弹框。进一步的攻击可以是构造一些表单进行提交(利用你的 Cookie 信息),达到黑客的某些目的(修改资料,窃取信息等等)。
第二种类型:存储型 XSS
用户的某些输入的数据(评论、留言等)可能会存储在服务器端,如果在显示这些数据前没有对这些数据进行处理的话,那么就可能会存在“ 存储型XSS”。
比较场景的一个场景就是,黑客写下一篇包含有恶意 JavaScript 代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的 JavaScript 代码。黑客把恶意的脚本保存到服务器端,所以这种 XSS 攻击就叫做“存储型XSS”。
存储型 XSS 通常也叫做“持久型 XSS”。
第三种类型:DOM Based XSS
通过修改页面的 DOM 节点形成的 XSS,称之为 DOM Based XSS。
假设有如下代码:
<script>
function test() {
var str = document.getElementById('text').value;
document.getElementById('t').innerHTML = "<a href = '" + str + "'>testLink</a>";
}
</script>
<div id="t"></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="write" onclick="test()" />
点击“write”按钮后,会在当前页面插入一个超链接,其地址为文本框的内容。
在这段代码中,“write”按钮的 onlick 事件绑定的函数修改了页面的 DOM 节点,通过 innerHTML 把一段用户数据当做 HTML 写入到页面中,这就有可能被利用进行 DOM Based XSS。
假使现在有人构造如下数据:
#' onclick=alert(/xss/) //
输入后,页面代码就变成了:
<a href='#' onclick=alert(/xss/) //'>testLink</a>
这时点击这个新生成的标签,脚本将被执行:
实际上,还有另一种利用方式——除了构造一个新事件外,还可以选择闭合掉 <a>
标签,并插入一个新的 HTML 标签。尝试如下输入:
'><img src=# onerror=alert(/xss2/) /><'
页面代码变成了:
<a href=''><img src=# onerror=alert(/xss2/) /><''> testLink</a>
这时,甚至不用点击标签,脚本就会被执行:
XSS 攻击手段有非常多,这里没法一一列举。理论上,针对HTML、CSS、JavaScript等输入数据做好过滤处理, XSS 漏洞是可以彻底解决的。
过滤处理这里不作介绍。
跨站点请求伪造(CSRF)
CSRF 的全名是 Cross Site Request Forgery,跨站点请求伪造。
注意请求伪造四个字。你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
下图简单阐述了 CSRF 攻击的思想:
从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
登录受信任网站A,并在本地生成Cookie。
在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了)
上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
上面大概地讲了一下CSRF攻击的思想,下面举个例子详细说说具体的CSRF攻击,这里我们以一个银行转账的操作作为例子。
银行网站A
,它以GET请求来完成银行转账的操作,如:http://www.mybank.com/Transfer?toBankId=11&money=1000
危险网站B
,它里面有一段 HTML 的代码如下:
<img src=http://www.mybank.com/Transfer?toBankId=11&money=1000>
首先,你登录了银行网站 A,然后访问危险网站 B,噢,这时你会发现你的银行账户少了1000块......
为什么会这样呢?原因是银行网站 A 使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站 A,而 B 中的<img>
以 GET 的方式请求第三方资源(银行网站),所以你的浏览器会带上你的银行网站 A 的 Cookie 发出 GET 请求,去获取资源http://www.mybank.com/Transfer?toBankId=11&money=1000
,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作。
这时你肯定会想,是不是改成 POST 提交表单就可以杜绝 CSRF 呢?
显然不是,这时只要网站 B 利用 HTML 或脚本构造出一个 POST 表单,再提交即可。
理解这种攻击模式,其实可以看出,CSRF 攻击是源于 Web 的 Cookie 身份验证机制!Web 的 Cookie验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。
如何防范 CSRF
防范 CSRF 方式方法很多样,但大部分的思想都是一致的,就是在客户端页面增加伪随机数。
验证码
最常见的方式就是,验证码。CSRF 攻击的过程,往往是在用户不知情的情况下构造了网络请求。而验证码,则强制用户必须与应用程序进行交互,才能完成最终请求。因此在通常情况下,验证码可以很好地遏制 CSRF 攻击。
但是,验证码并非万能。很多时候,出于用户体验考虑,网站不能给所有的操作都加上验证码。
这时可以用下面这种方案。
Anti CSRF Token
CSRF 为什么能够攻击成功?其本质原因是重要操作的所有参数都是可以被攻击者猜测到的。
攻击者只有预测出 URL 的所有参数与参数值,才能成功地构造出一个伪造的请求。
处于这个原因,可以想到一个解决方案:使用一些随机数,或者把参数加密。
最常见简单的方式是在表单中增加一个Token
随机值字段,因为存在同源政策,这时网站 B 想获取 token 来提交表单,难度就大大提升了。
<input type="hidden" name="token" value="ertf52342e21b">
或者使用一些随机数加载参数上,再把参数加密: 比如,一个删除操作的 URL 是:
http://www.yangzicong.com/user/delete?username=abc&item=123
把其中的 username 参数改成哈希值:
http://www.yangzicong.com/user/delete?username=md5(salt+abc)&item=123
这样,在攻击者不知道 salt 的情况下,是无法构造出这个 URL 的,因此也就无从发起 CSRF攻击了。
Referer Check
Referer Check 在互联网中最常见的应用就是“防止图片盗链”,例如微信公众号推文,当我们在其他网站上通过 iframe 引入微信推文时,推文里的图片会被屏蔽,这里就是用了图片防盗链。
同理,Referer Check 也可以被用于检查请求是否来自合法的“源”。
常见的互联网应用,页面与页面之间都具有一定的逻辑关系,这就使得每个正常的请求的 Referer 具有一定的规律。
比如一个“论坛发帖”的操作,在正常情况下需要先登录到用户后台,或者访问有发帖功能的页面。在提交“发帖”的表单时,Refer 的值必然是发帖表单所在的页面。如果Referer 的值不是这个页面,甚至不是发帖网站的域的时候,则极有可能 CSRF 攻击。
但缺陷是,服务器并非什么时候都能取到 Referer。很多用户出于隐私保护的考虑,限制了 Referer 的发送。在某些情况下,浏览器也不会发送 Referer,比如从 HTTPS 跳转到 HTTP。
所以,将 Referer Check 作为防御 CSRF 的主要手段是不可取的。但是通过 Referer Check 来进行辅助判断,倒是可行的方法。
这里我给师弟师妹们留两个问题:
- 什么是伪随机?我们常用的随机数是伪随机生成的吗?(与伪随机相对的是物理随机)
- GET 和 POST 请求有什么区别?(这个问题不急回答,慢慢积累,有新答案了告诉我)
点击劫持(ClickJacking)
简单介绍下点击劫持,点击劫持是 XSS 的引申,所以一般比较少见到,因为大部分网站的 XSS 防御都做得比较好。
点击劫持是一种视觉上的欺骗你手段。攻击者使用一个透明的、不可见的 iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作。当用户点击时,以为点击的是原页面上的按钮,但其实可能恰好点击在 iframe 页面的一些功能性按钮上。
通过不断调整 iframe 内页面元素的位置,或许能让用户完成一系列流程操作。具体是什么操作完全看攻击者的想象力了。
Flash 也存在点击劫持,一个比较严重的点击劫持攻击案例是:攻击者通过 Flash 构造出了点击劫持,在完成一系列复杂的动作后,最终控制了用户电脑的摄像头。
案例大概是,攻击者制作了一个 Flash 游戏,这个游戏就是让用户去点击某个小东西,每次点击后这个小东西的位置都会发生变化。通过一步一步的操作,打开了用户的摄像头。
还有很多意想不到的案例,可以自行去了解下,这里不再做介绍。
HTML5 安全
最后列一下 HTML5 的一些新功能及其会带来的安全问题。
- 一些 XSS Filter 如果是通过黑名单的方式过滤 XSS 攻击的化,可能不会覆盖到 HTML5 新增的标签和功能。如
<video>
标签或<audio>
标签,远程加载一段媒体资源,利用某些事件进行脚本攻击。 - HTML5 中
<a>
标签和<area>
标签定义的新标签属性noreferer
,在指定这个属性后,浏览器在请求该标签指定的地址时将不再发送Referer。 - 利用 Canvers 解析图片,在浏览器端自动破解验证码。
postMessage
、Web Storage
读取数据时也要注意对 XSS 的防范。(window.name
也需要)
相关书籍推荐:《白帽子讲Web安全》
(完)