同源策略
同源策略可以隔离各站点之间的 DOM 交互、页面数据和网络通信
严格的同源策略会带来更多的安全,但是也束缚了Web
这就需要在安全与自由之间找到一个平衡点
默认页面中可以引用任意第三方资源,这也暴露了诸如 XSS 的安全问题,因此又引入CSP策略来加以限制
默认 XMLHttpRequest 和 Fetch 不能跨站请求资源,然后又通过 CORS 策略来支持其跨域
默认不同源的 DOM 是不能相互操作的,因此又实现了跨文档消息机制,让其可以比较安全地通信
但与此同时,也就带来了很多安全问题,比如 XSS 攻击和CSRF攻击
XSS
跨站脚本攻击,指黑客往HTML文件或者DOM中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段
被注入恶意脚本后都能做哪些事情:
- 窃取Cookie信息
- 监听用户行为
- 修改 DOM
- 在页面内生成悬浮广告
诸如此类,还有很多,总之如果让页面注入恶意脚本,那么就相当于把我们页面的隐私数据和行为完全暴露给了黑客。
常见的注入方式
- 存储型 XSS 攻击
存储型 XSS 攻击大致需要经过如下步骤
1.利用站点漏洞将一段恶意代码提交到网站数据库中
2.用户向网站请求包含恶意代码的页面
3.当用户浏览该页面的时候,恶意脚本就会将用户的 Cookie 信息等数据上传到服务器
- 反射型 XSS 攻击
反射型 XSS 攻击过程中,恶意脚本属于用户发送给网站请求中的一部分,随后网站又把恶意脚本返回给用户,当恶意脚本在用户页面被执行时,就可以利用该脚本做一些恶意操作。
//例如当输入url为 ip:port/?xss=123 页面展示123
//那么当输入url为 ip:port/?xss=<script>alert('你被xss攻击了')</script> 就是反射型 XSS 攻击
与存储型 XSS 攻击不同的地方在于,Web 服务器不会存储反射型 XSS 攻击的恶意脚本
- 基于 DOM 的 XSS 攻击
基于 DOM 的 XSS 攻击是不牵扯到页面 Web 服务器的。是通过各种手段将恶意脚本注入用户的页面中,比如通过网络劫持修改 HTML 页面内容(比如 WiFi 路由器劫持)
如何阻止 XSS 攻击
存储型 XSS 攻击和反射型 XSS 攻击(经过Web服务器来处理的)-------服务器的安全漏洞
基于 DOM 的 XSS 攻击(全部都在浏览器端完成的)-------前端的安全漏洞
共同点:1.都需要往浏览器注入恶意脚本;2.通过恶意脚本将用户信息发送至恶意服务器上
阻止 XSS 攻击的思路: 通过阻止恶意脚本的注入和恶意消息的发送来实现
- 服务器对输入脚本进行过滤或转码
- 充分利用 CSP
- 限制加载其他域下的资源文件
- 禁止向第三方域提交数据
- 禁止执行行内脚本和未授权的脚本
- 提供上报机制,帮助尽快发现 XSS 攻击,以便尽快修复问题 - 使用 HttpOnly 属性来保护重要的 Cookie 信息(无法通过脚本读取 Cookie)
除了以上策略外,还可以通过添加验证码防止脚本冒充用户提交危险操作,对于一些不受信任的输入,可以限制其输入长度,这样可以增大 XSS 攻击的难度。
CSRF
CSRF 攻击就是黑客利用用户登录状态,并通过第三方的站点来做一些坏事。
和 XSS 不同的是,CSRF 攻击不需要将恶意代码注入用户页面,仅仅利用服务器的漏洞和用户登录状态来实施攻击。
发起 CSRF 攻击的三个必要条件:
- 目标站点存在 CSRF 漏洞
- 用户登录过目标站点,并保持有登录状态
- 用户打开一个第三方站点
常见的注入方式
- GET类型的CSRF
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
在受害者访问含有这个 img 的页面后,浏览器会自动向 http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker
发出一次 HTTP 请求。bank.example
就会收到包含受害者登录信息的一次跨域请求。
- POST类型的CSRF
这种类型的CSRF利用起来通常使用的是一个自动提交的表单,如:
<form action="http://bank.example/withdraw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
- 链接类型的CSRF
链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,例如:
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
重磅消息!!
<a/>
由于之前用户登录了信任的网站A,并且保存登录状态,只要用户主动访问上面的这个PHP页面,则表示攻击成功。
如何阻止 CSRF 攻击
主要的防护手段是提升服务器的安全性
-
充分利用好 Cookie 的 SameSite 属性,因为 Cookie 正是浏览器和服务器之间维护登录状态的一个关键数据,关于SameSite 的内容可详见链接
-
服务器端验证请求的来源站点,优先判断 Origin 其次是 Referer
-
CSRF Token
- 浏览器向服务器发起请求,服务器生成一个 CSRF Token
- 浏览器端需要发起请求时需要带上 CSRF Token,服务器会验证该 Token 是否合法
同源策略、CSP、CORS的关系
如果两个 URL 的协议、域名和端口都相同,我们就称这两个 URL 同源。浏览器默认两个相同的源之间是可以相互访问资源和操作 DOM 的。两个不同的源之间若想要相互访问资源或者操作 DOM,那么会有一套基础的安全策略的制约,我们把这称为同源策略。
主要表现
• DOM 层面
同源策略限制了来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作。
• 数据层面
同源策略限制了不同源的站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据。
• 网络层面
同源策略限制了通过 XMLHttpRequest 等方式将站点的数据发送给不同源的站点
安全和便利性
不过安全性和便利性是相互对立的,让不同的源之间绝对隔离,无疑是最安全的措施,但这也会使得 Web 项目难以开发和使用。因此我们就要在这之间做出权衡,出让一些安全性来满足灵活性;
出让的安全性
• 页面中可以嵌入第三方资源
页面中可以引用第三方资源,不过这也暴露了很多诸如 XSS 的安全问题,因此又在这种开放的基础之上引入了 CSP (内容安全策略)来限制其自由程度。CSP 的核心思想是让服务器决定浏览器能够加载哪些资源,让服务器决定浏览器是否能够执行内联 JavaScript 代码
• 跨文档消息机制
两个不同源的 DOM 是不能相互操纵的,浏览器中又引入了跨文档消息机制,可以通过 window.postMessage 的 JavaScript 接口来和不同源的 DOM 进行通信。
• 跨域资源共享
不同域之间使用 XMLHttpRequest 和 Fetch 都是无法直接进行跨域请求的,浏览器又在这种严格策略的基础之上引入了跨域资源共享策略(CORS),使用该机制可以进行跨域访问控制,从而使跨域数据传输得以安全进行。
参考文献
前端安全系列(一):如何防止XSS攻击?
前端安全系列之二:如何防止CSRF攻击?
浏览器工作原理与实践
浏览器安全机制