大概是关于浏览器安全的最全总结

我心飞翔 分类:javascript

总述

本文是关于浏览器安全协议、常见的Web攻击、Cookie机制的总结

  1. 浏览器安全协议: 什么是SOP/CORS/CSP? CORS协议为什么能保证安全,保证的是浏览器还是服务端的安全?
  2. 常见的Web攻击:什么是XSS攻击/XSRF攻击,有什么类型,怎么预防
  3. Cookie的作用是什么,其属性SameSite默认值在2020年发生改变带来的影响是什么?

浏览器安全协议

同源策略SOP

同源策略Same-origin policy:页面安全中最严格、最基础、最核心的安全策略

同源:URL的协议、域名和端口都相同

  • DOM层面: 限制了来自不同源的 Javascript脚本对当前DOM对象读和写的操作
  • 数据层面: 限制了不同源的站点读取当前站点的 Cookie、Indexdb、 Localstorage等数据。
  • 网络层面: 使用Xmlhttprequest和Fetch都是无法直接进行跨域请求的
    1. 跨域写操作(Cross-origin writes):一般是被允许的链接( links),重定向以及表单提交。
    2. 跨域资源嵌入(cross- origin embedding):一般是被允许,链接( links),重定向以及表单提交
    3. 跨域读操作(Cross-origin reads):ー般是不被允许的,但常可以通过內嵌资源来巧妙的进行读取访问。例如,你可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法

但这种限制过于严格,在实际使用中太过约束,所以实际的安全策略有所放宽

  1. 跨文档消息机制

    放松了DOM层面的约束:两个不同源的DOM是不能相互操纵的,但可以比较安全地通信

  2. 内容安全策略CSP

    放松了数据层面的约束:让服务器决定浏览器 能够加载哪些资源 是否能够执行内联 Javascript代码

  3. 跨域资源共享CORS

    放松了网络层面的约束(跨域读操作):进行跨域访问控制, 从而使跨域数据传输得以安全进行

跨域资源共享CORS

为什么CORS机制保证了跨域通信的安全?保证的是浏览器的安全还是服务端的安全?

之前开发时遇到cors,都是想尽一切办法,把浏览器控制台报错干掉,成功拿到数据

但一直没想通:为什么服务端在相应头里加上一句简单的access-control-allow-origin,就可以保证通信安全呢?这样保证了谁的安全呢

cors是浏览器的一套机制,服务端之间的通信是没有这套约束的,所以有人说 cors是为了保护浏览器的安全.但只要恶意站点把自己所有资源都加上这样的响应头,浏览器依旧会拿到恶意数据,这样的机制有什么意义呢?

其实cors的真正意义在于:浏览器保证损恶意攻击的成功,不是它的疏忽造成.

浏览器又叫user agent,用户代理。它作为一个容器,使得【恶意网站+被害用户+目标网站】有了相遇的机会。如果不加限制,恶意网站就可以利用浏览器 去达成攻击。

举个例子,在没有cors机制时,一个恶意网站如何利用浏览器中保存的用户登录凭证cookie,发起一个向fraud帐户的转账请求:

  1. 在用户登录目标网站victim.com后,目标网站返回一个登录凭证(set-Cookie=‘loginToken=1kqa23m6 ;domain=victim.com;path=/;sameSite:none;secure;’
  2. 用户不小心进入恶意站点evil.com.通过script脚本发起一个请求.自动发起请求.因为请求的url命中取用规则,cookie被携带上,并且,通过很简单的hack修改了请求头中的referer,从evil.com改为了victim.com
  3. 最终victim站点中招了

这便是一个CSRF攻击

浏览器对这次攻击有不可推卸的责任.

因为如果没有浏览器,恶意站点即便伪造请求,去修改referer,但是没有用户凭证,服务端不会判定这次请求成功

所以浏览器强制使用cors机制.其中关键在于origin.origin它是不能被用户代码修改的,只由当前所在站点决定,会诚实地告诉被害站点victim.com,本次请求来自evil.com这个恶意站点

然后由victim.com的服务端去校验,如果victim.com没有把evil.comr认做可信任源.那么在刚刚的例子中,这次跨域请求会在preflight预检阶段失败,真正的post转账请求没有发生,损失也就没有造成

所以除了get和表单post这种没有副作用请求,都会有一遍预检流程,而对于没有预检流程的简单请求,如果没有通过cors检查.请求已经发出去了,服务端也正常相应了.只是浏览器认为不安全,做了拦截

处理

  1. 简单请求

    • 请求方法是以下三种方法之一: HEAD GET POST
    • 请求头信息不超出以下几种字段Accept/Accept-Language/ content-Language/Last-Event-ID/Content-Type只限于三个值 [application/x-www-form-encoded;multipart/form-data;text/plain]

    直接发出CORS请求,在头信息之中,增加一个origin字段说明,本次请求来自哪个源

    服务器根据origin决定是否同意:Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。

    浏览器检查Access-Control-Allow-Origin >>如果浏览器指定的源Origin,不在许可范围内抛出一个错误,被Xmlhttprequest的onerror回调函数捕获。

无法通过状态码识别错误:因为HTTP回应的状态码有可能是200。

  1. 非简单请求

    • 请求方法是PUT 或 DELETE
    • 或者Content-Type是application/json

    正式通信之前,预检(preflight)浏览器先询问服务器"当前网页所在的域名origin是否许可+以使用哪些方法Access-Control-Request-Method+头信息字段Access-Control-Request-Headers"有得到肯定答复,浏览器オ会发出正式的Xmlhttprequest请求,否则就报错。

    预检请求的回应:如果服务器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段

    浏览器的正式请求和回应:通过了"预检"请求,每次请求,就都跟简单请求一样,会有一个origin头信息字段,响应也都会有一个 Access-Controll-Allow- Origin

字段
Origin:协议域名端口
Access-Control-Request-Headers:浏览器CORS请求会额外发送的头信息字段
Access-Control-Request-Methods:浏览器的CORS请求会用到哪些HTP方法
withCredentials:携带Cookie等HTTP认证信息跨域携带cookie
Access-Control-Allow-Credentials:是否允许发送 Cookie默认情況下, Cookie不包括在CORS请求之中。设为true,表示Cookies可以包含在请求跨域携带cookie
Access-Control-Allow-Origin:必须,要么是请求是Origin字段的值,要么是一个*,表示接受任意域名的请求跨域携带cookie
Access-Control-Expose-Headers:该字段可选。CORS请求时,Xmlhttprequest对象的getresponseheader()方法只能拿到6个基本字段: Cache- Contro1、 Content- Language、 Content-ype、 Expires、Last- Modified、 Pragma。如果想拿到其他字段,就必须在Access- Contro1- Expose- Headers里面指定。上面的例子指定, getres ponseheader(' Foobar')可以返回 Foobar字段的值。
Access-Control-Max-Age来指定本次预检请求的有效期,单位为秒在此期间,不用发出另一条预检请求。
Access-Control-Allow-Methods表明服务器支持的所有跨域请求的方法避免多次"预检"请求。
Access-Control-Allow-Header服务器支持的所有头信息字段,不限于浏览器在"预检”中请求的字段。
Content type:Form表单提交application/x-www-form-encoded图片上传multipart/form-dataJson对象application/json简单请求

跨域携带cookie:

如果要把 Cookie发到服务器,一方面要服务器同意,指定 Access-Controll-Allow-Credentials字段。
另一方面,请求头设置withcredentials属性。

需要注意的是,如果要发送 Cookie, Access-Controll-Allow-Origin就不能设为星号,必须指定明确Origin

表单跨域

史上表单一直可以发出跨域请求即便是更严格的sop协议。为了兼容表单(form), content-type设计如此,AJAX的跨域设计就是,只要表单可以发,AJAX就可以直接发。

两大web攻击

CSRF攻击——Cross-site request forgery

CSRF攻击的两个必要条件

  1. 拿到用户在目标站点的登录凭证
  2. 在恶意站点下向目标站点发起请求

为什么可以拿到用户登录凭证:在cookie的sameSite出现之前,cookie被浏览器与URL绑定.即浏览器在evil.com站点向victim.com站点发起请求:victim.com/transfer_to…
因为请求的host和path命中cookie的取用规则(无论是谁发起请求,都会带上cookie ) 这个请求就会带上用户在victim.com网站的登录凭证

如何发起请求:回标站点当然不会把恶意请求植入自己的负面 所以一般是从目标站点打开一个恶意站点,在恶意站点发起请求

邮箱漏洞:
David无意间打开了Gmai邮箱中的一份邮件,并点击了该邮件中的一个链接。过了几天, David就发现他的域名被盗了。不过几经周折, David还是要回了他的域名,也弄清楚了他的域名之所以被盗,就是因为无意间点击的那个链接。
首先 David发起登录 Gmail邮箱请求,然后 Gmail服务器返回一些登录状态给David的浏览器,这些信息包括了 Cookie、 Session等,这样在 David的浏览器中, Gmail邮箱就处于登录状态了。
接着黑客通过各种手段引诱David去打开他的链接,比如hacker.com,然后在hacker.com页面中,【黑客编写好了一个邮件过滤器,并通过Gmail提供的HTTP 设置接口设置好了新的邮件过滤功能,该过滤器会将 David所有的邮件都转发到黑客的邮箱中。】
所有行为都会被认为是David自己做的
因为有了 David的邮件内容,所以黑客就可以去域名服务商那边重置 David域名账户的密码,重置好密码之后,就可以将其转出到黑客的账户了

类型

自动发起POST请求

自动发起Get请求

引诱用户点击链接

这种方式在目标站点就可以发起攻击

预防

先分析一下出现这种危险的原因:

  1. 在页面中可以任意引用第三方资源,

  2. 让XmlhttpRequest和Fetch去跨域请求资源。

便可以找到预防措施了

  • Cookie-Samesite属性

  • CORS-Origin服务端验证请求的来源站点

  • CSRF Token/双重cookie

CSS.攻击——永远不信任用户输入

XSS与CSRF的区别:CSRF攻击不需要将恶意代码注入用户的页面,无法获取用户页面数据的仅仅是利用服务器的漏洞和用户的登录状态来实施攻击。

向HTML文件中注入恶意代码的

危害

  1. 窃取 Cookie信息

    恶意 Javascript可以通过“ document. cookie”获取Cookie信息,然后通过Xmlhttprequest或者Fetch加上CORS功能将数据发送给恶意服务器;恶意服务器拿到用户的 Cookie信息之后,就可以在其他电脑上模拟用户的登录,然后进行转账等操作。

  2. 监听用户行为

    恶意 Javascript可以使用' addeventlistener”接口来监听键盘事件,比如可以获取用户输入的信用卡等信息,将其发送到恶意服务器。黑客掌握了这些信息之后,又可以做很多违法的事情

  3. 修改DOM

    用来欺骗用户输入用户名和密码等信息

    在页面内生成浮窗广告

类型

存储型、反射型 和 基于DOM

Web服务器不会存储反射型XSS攻击的恶意脚本,这是和存储型XSS攻击不同的地方

  1. 存储型XSS攻击

    首先黑客利用站点漏洞将一段恶意 Javascript代码提交到网站的数据库中然后用户向网站请求包含了恶意 Javascript脚本的页面当用户浏览该页面的时候,恶意脚本就会将用户的 Cookie信息等数据上传到服务器。

  2. 反射型XSS攻击

    恶意 Javascript脚本属于用户发送给网站请求中的一部分,随后网站又把恶意 Javascript脚本返回给用户。当恶意 Javascript脚本在用户页面中被执行时,黑客就可以利用该脚本做一些恶意操作,黑客经常会通过QQ群或者邮件等渠道诱导用户去点击这些恶意链接

  3. 基于DOM的XSS攻击

    不牵涉到页面Web服务器的黑客通过各种手段将恶意脚本注入用户的页面中,比如通过网络劫持在页面传输过程中修改HTML页面的内容,这种劫持类型很多,有通过WiFⅰ路由器劫持的,有通过本地恶意软件来劫持的,它们的共同点是在Web资源传输过程或者在用户使用页面的过程中修改Web 页面的数据。

预防

存储型反射型都要服务器来处理,这两种类型是服务端的安全漏洞;而基于DOM全部都是在浏览器端完成的,因此是前端的安全漏洞

其过程是首先往浏览器中注入恶意脚本,然后再通过恶意脚本将用户信息发送至恶意服务器上

  1. 阻止恶意消息发送:

    • HttpOnly属性

      由于很多XSS攻击都是来盗用 Cookie的,因此还可以通过使用 Httponly .属性来保护我们 Cookie的安全。

    • 添加验证码

      防止脚本冒充用户提交

  2. 阻止脚本的注入:

    • 充分利用CSP

      限制加载其他域下的资源文件,这样即使黑客插入了一个 Javascript文件,这个Javascript文件也是无法被加载的(禁止向第三方域提交数据,这样用户数据也不会外泄;禁止执行内联脚本和未授权的脚本;还提供了上报机制,这样可以帮助我们尽快发现有哪些XSS攻击,以便尽快修复问题)

    • 服务器对输入脚本进行过滤或转码

      原始代码:

      code:<script>alert('??xss???')</script>
       

      过滤:image.png

      转码:image.png

充分利用CSP
限制加载其他域下的资源文件,这样即使黑客插入了一个 Javascript文件,这个Javascript文件也是无法被加载的

cookie

关于跨站和跨域/跨源

是不同的

同站(same-site)/跨站( cross-site)和第一方( first- party)/第三方( third- party)是等价的。

但是与浏览器同源策略(SOP)中的「同源(same- origin)/跨域( cross- origin)」是完全不同的概念

同站:只要两个URL的eTLD(有效顶级域名)+1相同即可,不需要考虑协议和端口。

有效顶级域名:(Public Suffix/eTLD)Mozilla维护,如.com、.co.uk、github.io等

例如taobao.com是一个站, www.taobao.com 和 www.baidu.com 是跨站,
www.taobao.com 和 static.taobao.com是同站;

.github.io和b.github.io是跨站(注意是跨站)

同源:指两个URL的协议/主机名/端口一致。

同源策略作为浏览器的安全基石,其「同源」判断是比较严格的,同站不一定同源,不同站一定不同源

属性

  • Expire / Max-age >>生命周期

    假如 Expires和Max-Age都存在,Max-Age优先级更高

    会话cookie: 最简单的,浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。不需要指定过期时间或者有效期值为Max-Age:Session

    它都应重新生成并重新发送会话 Cookie,甚至是已经存在的会话 Cookie。此技术有助于防止会话固定攻击( session fixation attacks)_,在该攻击中第三方可以重用用户的会话 >>

    持久cookie:生命周期取決于 过期时间( Expires)或 有效期(Max-Age)

    Expires:当 Cookie的过期时间被设定时,设定的日期和时间只与客户端相关,而不是服务端

    Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
     

    Max-Age:Max-Age用于设置在 Cookie失效之前需要经过的秒数。

    Set-Cookie: id=a3fWa; Max-Age=604800;
     

    如果max-Age属性为正数时,浏览器会将其持久化,即写到对应的 Cookie文件中。
    当max-Age属性为负数,则表示该 Cookie只是一个会话性 Cookie。
    当max-Age为0时,则会立即删除这个 Cookie。

  • Secure/HttpOnly >>限制访问

    Secure:只能通过HTTPS传输,预防中间人攻击,HTTP 接口不支持 SameSite=none

    但即便设置了 Secure标记,敏感信息也不应该通过Cookie传输,因为 Cookie有其固有的不安全性, Secure标记也无法提供确实的安全保障,例如,可以访问客户端硬盘的人可以读取它。

    Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly >>
     

    http only:持久化服务器端会话的 Cookie不需要对 Javascript可用只要是httponly类型的,在控制台通过document.cookie是获取不到的,也不能进行修改。

    可以预防(XSS)攻击

  • Domain path/SameSite >>作用域

    同决定了cookie何时被浏览器自动添加到请求头部中发送出去

    父域名或者父路径都不可以使用

    Domain:指定了可以携带该cookie的URL。

    设置:如果不指定,默认值为设置该cookie的网页所在的域名,不能除当前域名或者其父域名之外的其他domain;但不能是公共后缀 public suffix

    比如www.baidu.com, domain可以设置为“www.baidu.com”,也可以设置为“baidu.com”,但不能设置为“.com”或“com”。

    当前大多数浏览器遵循RFC6265口,设置 Domain时不需要加前导点。浏览器不遵循该规范,则需要加前导点,例如: Domain=,mozi11a.org >>

    使用:本域名 与 其子域,如果不指定,默认为origin,但子域名不可用;如果指定了 Domain 为origin,则包含子域名。

    例如,如果设置 Domain=mozilla.org,则 Cookie 也包含在子域名中(如developer.mozilla.org。因此,指定 Domain比省略它的限制要少

    Path:标识指定了主机下的哪些路径可以接受 Cookie

    设置: 默认为请求 uri 的路径,URL路径必须存在于请求URL中;path 应该以 "/" 结尾

    使用: 默认为请求 uri 的路径;当URI的path值是以“/”结尾的时候,直接设置为cookie的path值;当URI的path值不是以“/”结尾的时候,查看path里面是否有“/”;如果有“/”的话,直接截取到最后一个“/”,然后设置为cookie的path值。

如果没有“/”的话,将cookie的path设置为”/”。.但不会像domain那样影响子路径

  • SameSite >>

    限制三方/跨站cookie:可以让 Cookie在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击

    修改:之前獸认是None的, Chrome80后默认是Lax。

    影响:表单,iframe,AJAX,Image 这四种情况从以前的跨站会发送三方 Cookie,变成了不发送

    image.png

    取值

    1. Strict仅允许一方请求携带Cookie,即浏览器将只发送相同站点请求的 Cookie,即当前网页URL与请求目标URL完全一致

    2. Lax允许部分第三方请求携带Cookie

    3. None无论是否跨站都会发送Cookie

    HTTP 接口不支持 SameSite=none;想加 SameSite=none 属性,那么该 Cookie 就必须同时加上 Secure 属性,表示只有在HTTPS 协议下该 Cookie 才会被发送

  • Name/Value:用 Javascript操作 Cookie的时候注意对于Value值,最好用encodeURIComponent 对其编码

    Cookie前缀:Name 前缀为__ Secure- 或 __Host,只可以应用在使用了安全连接(HTTPS)的域中,需要同时设置 secure以 __Host- 为前缀,path 属性的值必须为 "/" (表示整个站点)不能含有 domain 属性。// 当响应来自于一个安全域(HTTPS)的时候,二者都可以被客户端接受

Set-Cookie: __Secure-ID=123; Secure; Domain=example.com
Set-Cookie: __Host-ID=123; Secure; Path=/
// 缺少 Secure 指令,会被拒绝
Set-Cookie : __Secure-id=1
// 缺少 Path=/ 指令,会被拒绝
Set-Cookie: __Host-id=1; Secure
// 由于设置了 domain 属性,会被拒绝
Set-Cookie: __Host-id=1; Secure; Path=/; domain=example.com
 
子域上的易受攻击的应用程序可以使用 Domain属性设置 cookie,从而可以访问所有其他子域上的该 cookie。会话固定攻击中可能会滥用此机制。
 

回复

我来回复
  • 暂无回复内容