浏览器中的安全,可以按照系统安全、网络安全、页面安全三个方面来了解。
浏览器系统安全
谁也无法保证浏览器自身不存在漏洞,浏览器在执行前又无法分辨从网络拿到的资源是否安全,而操作系统的各种权限让网络资源接触到是有风险的,因此默认所有网络资源都是不可信的。
现代浏览器早已经拥抱了多进程的架构,从输入 url 到页面展示,浏览器中多个进程通力合作,让用户看到一个期望的图像,其中最重要的一个进程,渲染进程,是执行网络资源的关键进程,因此浏览器通过安全沙箱,把渲染进程包了起来。
安全沙箱
安全沙箱最小的保护单位是进程,安全沙箱会限制进程对操作系统资源的访问/修改。
需要注意的是,tab 和渲染进程并不是一对一的关系:
同一站点的意思是,协议和根域名相同,与同源相比,判断条件宽松许多;而连接关系的意思是,b 页面是在 a 页面中通过 window.open ——此时可以在 a 中使用 window.open 的返回控制 b 页面;或者 a target="_blank" ——此时可以在 b 中通过 window.opener 控制 a ——的方式打开的。
网络安全
http 生来为传输 html ,但随着 web 的发展,http 的功能越来越不够用,伴随着功能上的完善,网络安全问题也成为重要研究对象。
http 的风险有三点:
-
窃听风险:第三方可以获知通信内容
-
篡改风险:第三方可以修改通信内容
-
冒充风险:第三方可以冒充他人身份参与通信
为此, TCP 和 HTTP 之间被插入一个安全层,所有经过的数据会被加密/解密。
接入了安全层的 http 变成了 https ,它的特点有:
-
所有信息都是加密传播,第三方无法窃听。
-
具有校验机制,一旦被篡改,通信双方会立刻发现。
-
配备身份证书,防止身份被冒充。
怎么实现呢?
https 加密过程
一个重要的规则是,公钥加密的数据只有私钥能解密。
公钥是明文的,黑客容易破解,但私钥只有服务器有,而 pre-master 是公钥加密生成的,因此只有服务器能破解。最终的 master secret 有了 pre-master 的参与,数据发送和接受了都很安全。
而且,只需要进行一次非对称加密就可以了,传输效率也比较高。
当然,黑客服务器自己生产公钥私钥,客户端可能进入假的页面。服务器怎么证明自己是真实合法的呢?数字证书。
CA 证书
CA是一个机构,它的职责是给一些公司或者个人颁发数字证书。
数字证书需要申请,流程如下:
CA 审核是线上线下结合的,很多时候线下审核依赖本地政策,于是现实中需要分级治理,进而形成了一个 CA 链。浏览器验证的时候会沿着 CA 链向上寻找,直到根 CA:
即便黑客伪造了服务器,但是由于证书是没有办法伪造的,无法欺骗用户。
页面安全
页面经过 https 请求资源、安全沙箱渲染出来,执行脚本时,可能会有一些恶意脚本被执行;或者,用户受到诱惑,点击了一些通往恶意站点的链接时,可能出现什么情况呢?
-
DOM、CSSOM 被修改
-
用户行为受到监听
-
敏感信息遭到劫持
-
Cookie、indexDB 等数据被读取、上传、使用
-
用户请求被伪造
没有安全保障的 web 世界很可怕,无序、充满陷阱。而页面中最基础、最核心的安全策略是什么?
同源策略( Same-origin policy )。
不同源的 js 脚本无法读写当前页面的 DOM;不同源的 js 脚本无法读取当前页面的 Cookie、IndexDB、LocalStorage 等;不同源的 XMLHttpRequest 访问无法进行。
这样一来,很多正常的事情也变得不太方便了,比如 cdn 资源请求。因此为了一些便利性,同源策略给第三方资源发了通行证,这样一来,安全问题产生了。
典型的安全攻击有:XSS (Cross-site script) 和 CSRF (Cross-site request forgery,跨站请求伪造)。
顾名思义,前者以插入脚本读取敏感为主,后者则非法使用 cookie 伪造用户请求达到不可告人的目的。
XSS 攻击
三种常用的 XSS 攻击方法。
存储型,可能是利用内容管理系统的漏洞,向服务器发送了恶意代码:
反射型,与存储型 xss 攻击不同的是,服务器不存储恶意代码:
基于 DOM 的攻击:
那如何阻止 XSS 攻击呢?
-
服务器对输入的脚本进行过滤/转码
-
使用 CSP (内容安全策略)让服务器决定浏览器可以加载哪些资源,执行哪些脚本。
CSP 不仅可以规定资源来源,还可以禁止脚本向第三方提交数据,同时在出现异常时,也能向维护人员及时上报异常。
CSRF 攻击
CSRF 攻击不需要在页面中注入脚本,而是利用用户的登录状态和服务器的漏洞,通过第三方站点做一些坏事,比如自动转发邮件,转账等等,但是有两个前提:
1、服务端有漏洞;2、用户要点击黑客页面的链接。
举个例子,如下代码的页面被加载时,浏览器会自动发起 img 的资源请求,如果服务器没有对请求类型做判断,把图片资源当作 xhr 请求处理了,钱就被转走了:
<!DOCTYPE html> <html><body><img src=“https://www.pay.com/sendmoney?user=badbuys&number=1个亿” /></body> </html>
或者点击恶意链接,如下代码的页面被加载时,表单会被自动执行提交:
<!DOCTYPE html> <html><body><form id=“terrible-form” action=““https://www.pay.com/sendmoney” method=“POST”><input type=“hidden” name=“user” value=“badbuys” /><input type=“hidden” name=“number” value=“1个亿” /></form><script>document.getElementById(‘terrible-form’).submit();</script></body> </html>
又或者一个诱惑链接:
<!DOCTYPE html> <html><body><img src=“一个很性感的美女” /><a href=“https://www.pay.com/sendmoney?user=badbuys&number=1个亿”>点击下载美图图片</a><a href=“https://www.pay.com/sendmoney?user=badbuys&number=2个亿”>点击和美女视频聊天</a></body> </html>
如何防止 CSRF 攻击呢?
我们需要提升服务器的安全性。
-
从第三方站点发送请求时,禁止发送 Cookie —— set-cookie 中设置 SameSite 为 Strict
-
验证请求的来源站点 —— 通过 Request Header: Referer || Origin
-
CSRF Token 验证,服务器要求所有请求必须携带 CSRF Token ,第三方无法拿到 Token ,伪造的请求会被拒绝访问
--end--