浅谈前端安全

本文讲了浅谈前端安全,前端安全性问题解决方案。

1 什么是前端安全?

所有发生在浏览器、单页面应用、Web页面当中的安全问题都算是算是“前端安全问题”。或者就是说所有需要前端开发人员去修复的问题都属于前端安全问题。

2 前端目前存在哪些安全问题

2.1 xss(Cross Site Scripting)跨站脚本攻击

原理

xss说白了就是攻击者想尽一切的方法,将可执行的代码注入到我们的页面中,让页面进行一些非法的操作(浏览器错误的将攻击者输入的数据当做JavaScript脚本给执行了)。

xss从攻击的时间上可以分为持久型(存储型)攻击和非持久型(反射型)攻击。

持久型

持久型的就是指攻击者通过我们的页面,将具有攻击性的代码通过服务器保存到了数据库中,导致其他的用户在浏览当前页面时,受到了攻击。最常见的就是具有评论功能的页面。

非持久型

非持久型相比于持久型攻击危害就小的多了,一般通过修改 URL 参数的方式加入攻击代码,诱导用户访问链接从而进行攻击。

场景

1.页面中所有的input框

2.window.location(href、hash等)

3.window.name

4.document.referrer // 保存着链接到当前页面的那个页面的URL。

5.document.cookie

6.localstorage

7.XMLHttpRequest返回的数据

危害

网络钓鱼,包括盗取各类用户账号;

窃取用户cookies资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作;

劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等;

强制弹出广告页面、刷流量等;

网页挂马;进行恶意操作,例如任意篡改页面信息、删除文章等 进行大量的客户端攻击,如DDoS攻击;

获取客户端信息,例如用户的浏览历史、真实IP、开放端口等;

控制受害者机器向其他网站发起攻击;

结合其他漏洞,如CSRF漏洞,实施进一步作恶;

提升用户权限,包括进一步渗透网站;

传播跨站脚本,蠕虫等;

防御

防御的方式总的来说就是两方面。一方面是验证所有输入数据,有效检测攻击;另一方就是对所有输出数据进行适当的编码,以防止任何已成功注入的脚本在浏览器端运行。

转义字符

  1. 一般会转(&、<、>、"、’、/)这6个字符。

比如说将<script></script>转换成&lt;script&gt&lt;/script&gt

这样浏览器就不会将这段代码当做js来执行了。

CSP(内容安全策略)

CSP通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。一个CSP兼容的浏览器将会仅执行从白名单 域获取到的脚本文件,忽略所有的其他脚本

(包括内联脚本和HTML的事件处理属性)。

当然除了可以指定域之外,还可以指定加载脚本的协议,比如只允许访问https的脚本

Content-Security-Policy主要有以下几大分类

等等等还有好多,还没有整体出来

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">

2.2 CSRF(Cross Site Request Forgery)跨站请求伪造

原理

CSRF(Cross Site Request Forgery),即跨站请求伪造,是一种常见的Web攻击。CSRF攻击过程的受害者用户登录网站A,输入个人信息,在本地保存服务器生成的cookie。然后在A网站点击由攻击者构建一条恶意链接跳转到B网站,然后B网站携带着的用户cookie信息去访问B网站。让A网站造成是用户自己访问的假相,从而来进行一些列的操作,常见的就是转账。

场景

网站使用Cookie验证用户

用户没有登出网站

网站没有做任何CSRF的防御

危害

通过基于受信任的输入form和对特定行为无需授权的已认证的用户来执行某些行为的web应用。已经通过被保存在用户浏览器中的cookie进行认证的用户将在完全无知的情况下发送HTTP请求到那个信任他的站点,进而进行用户不愿做的行为。

防御

大致要遵循以下几点规则:

  1. Get 请求不对数据进行修改

  2. 不让第三方网站访问到用户 Cookie

  3. 阻止第三方网站请求接口

  4. 请求时附带验证信息,比如验证码或者Token

  5. SameSite: Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。

  6. 验证 Referer, 验证一下发起请求的页面是不是我们的系统

  7. Token:发送一个带有过期时间的token

  8. 跨域资源共享(CORS)

    • 大多数情况下,为了省事,都配置为*,这样就会存在很大的安全隐患。
    • 普通跨域请求: 只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。

2.3 SQL脚本注入(SQL Injection)

原理

SQL注入(SQL Injection),应用程序在向后台数据库传递SQL(Structured Query Language,结构化查询语言)时,攻击者将SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

1.是一种将SQL语句插入或添加到应用(用户)的输入参数中的攻击

2.这些参数传递给后台的SQL数据库服务器加以解析并执行

危害

1.获取不属于当前用户的管理权限

2.对数据库进行增删改查

防御

1、增加黑名单或者白名单验证

白名单验证一般指,检查用户输入是否是符合预期的类型、长度、数值范围或者其他格式标准。黑名单验证是指,若在用户输入中,包含明显的恶意内容则拒绝该条用户请求。在使用白名单验证时,一般会配合黑名单验证。

2、安全检测

在项目完成的时候,始终坚持安全检测。

3、防止系统敏感信息泄露: 对数据表的访问权限进行严格控制,尽量限制用户不必要的访问权限

2.4 上传漏洞

原理

指攻击者上传了一个可执行的文件到服务器并能够成功执行。

危害

上传漏洞与SQL注入或 XSS相比 , 其风险更大 , 如果 Web应用程序存在上传漏洞 ,攻击者上传的文件是Web脚本语言,服务器的Web容器解释并执行了用户上传的脚本,导致代码执行。如果上传的文件是Flash的策略文件crossdomain.xml,黑客用以控制Flash在该域下的行为。如果上传的文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行。如果上传的文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。甚至攻击者可以直接上传一个webshell到服务器上

完全控制系统或致使系统瘫痪。

防御

客户端: javascript校验(一般只校验后缀名)

服务端校验: 文件头content-type字段校验(image/gif)

文件内容头校验(GIF89a)

后缀名黑名单校验

后缀名白名单校验

自定义正则校验

2.5 控制台输入

危害

  • XSS攻击:攻击者可以在控制台中输入恶意脚本,并将其注入到网站中,从而在用户浏览网站时窃取用户的敏感信息,如登录凭证、cookie等。

  • CSRF攻击:攻击者可以利用控制台修改网站上的表单和数据,从而发起跨站请求伪造攻击,使用户在不知情的情况下执行恶意操作。

  • 破坏网站功能:攻击者可以通过控制台修改网站上的JavaScript代码,从而破坏网站的正常功能,如禁用按钮、修改网页内容等。

  • 窃取用户信息:攻击者可以通过控制台修改网站的JavaScript代码,从而捕获用户的输入数据并将其发送到攻击者的服务器,从而窃取用户的敏感信息。

防御

  • 使用CSP(Content Security Policy)来限制JavaScript的来源,防止XSS攻击。

  • 使用CSRF Token来防止CSRF攻击。

  • 对用户输入进行有效的验证和过滤,以防止恶意代码注入。

  • 在生产环境下禁用控制台调试功能,以防止攻击者利用控制台进行攻击。

  • 对于需要进行敏感操作的页面,应该使用HTTPS协议来加密通信,以保护用户的隐私信息。

2.6 img标签的再次利用 onerror事件

原理

通过将图片地址认为的设置错误,从而引发执行onerror事件.

危害

系统执行攻击者的 代码,造成数据泄露

防御

可以参考CSP(内容安全策略)

2.7 点击劫持

原理

这是一种欺骗性比较强,同时也需要用户高度参与才能完成的一种攻击。

通常的攻击步骤是这样的:

1、攻击者构造一个诱导用户点击的内容,如Web页面小游戏

2、将被攻击的页面放入到iframe当中

3、利用z-index等CSS样式将这个iframe叠加到小游戏的垂直方向的正上方

4、把iframe设置为100%透明度

5、受害者访问这个页面,肉眼看到的是一个小游戏,如果受到诱导进行了点击的话,实际上点击到的却是iframe中的页面

危害

点击劫持的危害在于,攻击利用了受害者的用户身份,在其不知情的情况下进行一些操作。

防御

X-FRAME-OPTIONS

设置页面是否可以在标签中显示

1、DENY:不能被嵌入到任何iframe或者frame中。

2、SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中

3、ALLOW-FROM uri:只能被嵌入到指定域名的框架中

JS 防御

<head>
  <style id="click-jack">
    html {
    display: none !important;
    }
  </style>
</head>
<body>
  <script>
    if (self == top) {
    var style = document.getElementById('click-jack');
    document.body.removeChild(style);
    } else {
    top.location = self.location;
    }
  </script>
</body>
<head>
  <style id="click-jack">
    html {
    display: none !important;
    }
  </style>
</head>
<body>
  <script>
    if (self == top) {
    var style = document.getElementById('click-jack');
    document.body.removeChild(style);
    } else {
    top.location = self.location;
    }
  </script>
</body>

以上代码的作用就是当通过 iframe 的方式加载页面时,攻击者的网页直接不显示所有内容了。

2.8 本地存储数据泄露

前端应用是完全暴露在用户以及攻击者面前的,在前端存储任何敏感、机密的数据,都会面临泄露的风险,就算是在前端通过JS脚本对数据进行加密基本也无济于事。

2.9 iframe的安全属性 sandbox

原理

有时候前端页面为了显示别人的网站或者一些组件的时候,就用iframe来引入进来,比如嵌入一些广告等等。但是有些iframe安全性我们无法去评估测试,有时候会携带一些第三方的插件啊,或者嵌入了一下不安全的脚本啊,这些都是值得我们去考虑的。

防御

在iframe的标签中添加 sandbox = “”, 将开启一下所有的限制

配置 效果

allow-forms 允许进行提交表单

allow-scripts 运行执行脚本

allow-same-origin 允许同域请求,比如ajax,storage

allow-top-navigation 允许iframe能够主导window.top进行页面跳转

allow-popups 允许iframe中弹出新窗口,比如,window.open,target=“_blank”

allow-pointer-lock 在iframe中可以锁定鼠标,主要和鼠标锁定有关

2.10 不安全的第三方依赖 CDN

原理

在我们的系统中引用的一些在线的第三方库,可能会存在被别人贡献的危害,是的我们的系统中执行一些非常规的操作

2.11 登录的账号密码不能明文传输

2.12 https安全加密

随着大前端的快速发展,各种技术不断更新,前端的安全问题也值得我们重视。今天我们来聊一聊前端常见的7个安全方面问题:
1.iframe
2.opener
3.CSRF(跨站请求伪造)
4.XSS(跨站脚本攻击)
5.ClickJacking(点击劫持)
6.HSTS(HTTP严格传输安全)
7.CND劫持

iframe

1.如何让自己的网站不被其他网站使用iframe引用

if(top.location !== window.location){
  top.location.href = xxx
}
if(top.location !== window.location){
  top.location.href = xxx
}

当发现我们的网站被其他网站引用时,可以强制使网站跳转到其他网站。

2.如何禁用,被使用的 iframe 对当前网站某些操作?

sandbox是html5的新属性主要是提高iframe安全系数iframe因安全问题而臭名昭著这主要是因为iframe常被用于嵌入到第三方中然后执行某些恶意操作
现在有一场景我的网站需要 iframe 引用某网站但是不想被该网站操作DOM不想加载某些js广告弹框等)、当前窗口被强行跳转链接等我们可以设置 sandbox 属性如使用多项用空格分隔
sandbox是html5的新属性主要是提高iframe安全系数iframe因安全问题而臭名昭著这主要是因为iframe常被用于嵌入到第三方中然后执行某些恶意操作
现在有一场景我的网站需要 iframe 引用某网站但是不想被该网站操作DOM不想加载某些js广告弹框等)、当前窗口被强行跳转链接等我们可以设置 sandbox 属性如使用多项用空格分隔

参考:HTML sandbox 属性

  • allow-same-origin:允许被视为同源,即可操作父级DOM或cookie等

  • allow-top-navigation:允许当前iframe的引用网页通过url跳转链接或加载

  • allow-forms:允许表单提交

  • allow-scripts:允许执行脚本文件

  • allow-popups:允许浏览器打开新窗口进行跳转
    “”:设置为空时上面所有允许全部禁止

opener

如果在项目中需要 打开新标签 进行跳转一般会有两种方式:

  1. HTML:
<a target='_blank' href='http://www.baidu.com'>
<a target='_blank' href='http://www.baidu.com'>
  1. JS:
window.open('http://www.baidu.com')
window.open('http://www.baidu.com')

这两种方式看起来没有问题,但是存在漏洞。

  • 通过这两种方式打开的页面可以使用 window.opener 来访问源页面的 window 对象。
  • 场景:A 页面通过 <a>window.open 方式,打开 B 页面。但是 B 页面存在恶意代码如下:
window.opener.location.replace('https://www.baidu.com') 
window.opener.location.replace('https://www.baidu.com') 

【此代码仅针对打开新标签有效】

  • 此时,用户正在浏览新标签页,但是原来网站的标签页已经被导航到了百度页面。
  • 恶意网站可以伪造一个足以欺骗用户的页面,使得进行恶意破坏。
  • 即使在跨域状态下 opener 仍可以调用 location.replace 方法。

针对窃取 window.opener 的问题,常见的防御方案有以下几种:

  1. 使用 rel=“noopener” 或 rel=“noreferrer” 属性,这样就可以防止新打开的页面可以通过 window.opener 访问到原始页面的 window 对象。
  <a target="_blank" href="http://www.baidu.com" rel="noopener">打开百度</a>
  <a target="_blank" href="http://www.baidu.com" rel="noopener">打开百度</a>
  1. 采用 window.postMessage() 方法进行消息传递。在打开新页面时,可以向新页面传递一个消息,然后在新页面中通过监听 message 事件来接收消息。这样就可以避免窃取 window.opener 的问题。
   // 在原始页面中
   var newWindow = window.open('http://www.baidu.com');
   newWindow.postMessage('hello', 'http://www.baidu.com');

   // 在新打开的页面中
   window.addEventListener('message', function(event) {
       if (event.origin !== 'http://www.baidu.com') return;
       console.log(event.data); // 输出 "hello"
   });
   // 在原始页面中
   var newWindow = window.open('http://www.baidu.com');
   newWindow.postMessage('hello', 'http://www.baidu.com');

   // 在新打开的页面中
   window.addEventListener('message', function(event) {
       if (event.origin !== 'http://www.baidu.com') return;
       console.log(event.data); // 输出 "hello"
   });
  1. 在服务器端进行验证。在跳转到新页面之前,服务器端可以对用户进行身份验证,然后将用户的身份信息传递到新页面中。这样即使窃取了 window.opener,也无法进行恶意操作,因为服务器会对用户的身份进行验证。
  // 在原始页面中
  var newWindow = window.open('/newpage');
  
  // 在服务器端
  app.get('/newpage', function(req, res) {
      if (req.isAuthenticated()) {
          // 用户已经登录,可以安全跳转到新页面
          res.render('newpage', { user: req.user });
      } else {
          // 用户未登录,跳转到登录页面
          res.redirect('/login');
      }
  });
  // 在原始页面中
  var newWindow = window.open('/newpage');
  
  // 在服务器端
  app.get('/newpage', function(req, res) {
      if (req.isAuthenticated()) {
          // 用户已经登录,可以安全跳转到新页面
          res.render('newpage', { user: req.user });
      } else {
          // 用户未登录,跳转到登录页面
          res.redirect('/login');
      }
  });

CSRF / XSRF(跨站请求伪造)

你可以这么理解 CSRF 攻击:攻击者盗用了你的身份,以你的名义进行恶意请求。它能做的事情有很多包括:以你的名义发送邮件、发信息、盗取账号、购买商品、虚拟货币转账等。总结起来就是:个人隐私暴露及财产安全问题。

/*
 * 阐述 CSRF 攻击思想:(核心2和3) * 1、浏览并登录信任网站(举例:淘宝) * 2、登录成功后在浏览器产生信息存储(举例:cookie) * 3、用户在没有登出淘宝的情况下,访问危险网站 * 4、危险网站中存在恶意代码,代码为发送一个恶意请求(举例:购买商品/余额转账) * 5、携带刚刚在浏览器产生的信息进行恶意请求 * 6、淘宝验证请求为合法请求(区分不出是否是该用户发送) * 7、达到了恶意目标 */
/*
 * 阐述 CSRF 攻击思想:(核心2和3) * 1、浏览并登录信任网站(举例:淘宝) * 2、登录成功后在浏览器产生信息存储(举例:cookie) * 3、用户在没有登出淘宝的情况下,访问危险网站 * 4、危险网站中存在恶意代码,代码为发送一个恶意请求(举例:购买商品/余额转账) * 5、携带刚刚在浏览器产生的信息进行恶意请求 * 6、淘宝验证请求为合法请求(区分不出是否是该用户发送) * 7、达到了恶意目标 */

一般CSRF形式上有三种表现:
1.自动发起 Get 请求
模拟代码如下:

1 <!DOCTYPE html> <html><body> <h1> 黑客的站点:CSRF 攻击演示 </h1> <img src="https://time.geekbang.org/sendcoin?user=hacker&number=100"></body> </html>
1 <!DOCTYPE html> <html><body> <h1> 黑客的站点:CSRF 攻击演示 </h1> <img src="https://time.geekbang.org/sendcoin?user=hacker&number=100"></body> </html>

攻击者将请求转账的链接隐藏在精美的图片里,当你点击时,就会想服务器发起请求。

2.自动发起 POST 请求
模拟代码如下:

<!DOCTYPE html> <html><body><h1> 黑客的站点:CSRF 攻击演示 </h1><form id='hacker-form' action="https://time.geekbang.org/sendcoin" method="POST"><input type="hidden" name="user" value="hacker" /><input type="hidden" name="number" value="100" /> </form> <script>document.getElementById('hacker-form').submit(); 
</script></body> </html>
<!DOCTYPE html> <html><body><h1> 黑客的站点:CSRF 攻击演示 </h1><form id='hacker-form' action="https://time.geekbang.org/sendcoin" method="POST"><input type="hidden" name="user" value="hacker" /><input type="hidden" name="number" value="100" /> </form> <script>document.getElementById('hacker-form').submit(); 
</script></body> </html>

在这段代码中,我们可以看到黑客在他的页面中构建了一个隐藏的表单,该表单的内容就是极客时间的转账接口。当用户打开该站点之后,这个表单会被自动执行提交;当表单被提交之后,服务器就会执行转账操作。因此使用构建自动提交表单这种方式,就可以自动实现跨站点 POST 数据提交。

  1. 引诱用户点击链接
    除了自动发起 Get 和 Post 请求之外,还有一种方式是诱惑用户点击黑客站点上的链接,这种方式通常出现在论坛或者恶意邮件上。黑客会采用很多方式去诱惑用户点击链接,示例代
    码如下所示:
<div> <img width=150 src=http://images.xuejuzi.cn/1612/1_161230185104_1.jpg> </img> <a href="https://time.geekbang.org/sendcoin?user=hacker&number=100" taget="_b 4 点击下载美女照片</a> 
</div>
<div> <img width=150 src=http://images.xuejuzi.cn/1612/1_161230185104_1.jpg> </img> <a href="https://time.geekbang.org/sendcoin?user=hacker&number=100" taget="_b 4 点击下载美女照片</a> 
</div>

这段黑客站点代码,页面上放了一张美女图片,下面放了图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接,那么他的极客币就被转到黑客账户上了。

解决方案:

  • 利用好 Cookie 的 SameSite 属性
 HTTP 响应头中通过 set-cookie 字段设置 Cookie 可以带上 SameSite 选项如下set-cookie: 1P_JAR=2019-10-20-06; expires=Tue, 19-Nov-2019 06:36:21 GMT;SameSite=Strict;
SameSite 选项通常有 StrictLax  None 三个值Strict 最为严格如果 SameSite 的值是 Strict那么浏览器会完全禁止第三方Cookie简言之如果你从极客时间的页面中访问 InfoQ 的资源 InfoQ 的某些Cookie 设置了 SameSite = Strict 的话
那么这些 Cookie 是不会被发送到 InfoQ 的服务器上的只有你从 InfoQ 的站点去请求 InfoQ 的资源时才会带上这些 Cookie
Lax 相对宽松一点在跨站点的情况下从第三方站点的链接打开和从第三方站点提交Get 方式的表单这两种方式都会携带 Cookie但如果在第三方站点中使用 Post 方法或者通过 imgiframe 等标签加载的 URL
这些场景都不会携带 Cookie
而如果使用 None 的话在任何情况下都会发送 Cookie 数据
 HTTP 响应头中通过 set-cookie 字段设置 Cookie 可以带上 SameSite 选项如下set-cookie: 1P_JAR=2019-10-20-06; expires=Tue, 19-Nov-2019 06:36:21 GMT;SameSite=Strict;
SameSite 选项通常有 StrictLax  None 三个值Strict 最为严格如果 SameSite 的值是 Strict那么浏览器会完全禁止第三方Cookie简言之如果你从极客时间的页面中访问 InfoQ 的资源 InfoQ 的某些Cookie 设置了 SameSite = Strict 的话
那么这些 Cookie 是不会被发送到 InfoQ 的服务器上的只有你从 InfoQ 的站点去请求 InfoQ 的资源时才会带上这些 Cookie
Lax 相对宽松一点在跨站点的情况下从第三方站点的链接打开和从第三方站点提交Get 方式的表单这两种方式都会携带 Cookie但如果在第三方站点中使用 Post 方法或者通过 imgiframe 等标签加载的 URL
这些场景都不会携带 Cookie
而如果使用 None 的话在任何情况下都会发送 Cookie 数据
  • 验证请求的来源站点
    利用http请求头中的referer或者origin字段告诉服务器请求来源,让服务端判断自否禁止该请求。

  • CSRF Token
    除了使用以上两种方式来防止 CSRF 攻击之外,还可以采用 CSRF Token 来验证,这个流程比较好理解,大致分为两步:
    第一步,在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。你可以参考下面示例代码:

    第二步,在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token,然后服务器会验证该 Token 是否合法。如果是从第三方站点发出的请求,那么将无法获取到CSRF Token 的值,
    所以即使发出了请求,服务器也会因为 CSRF Token 不正确而拒绝请求。

XSS/CSS(跨站脚本攻击)

XSS 全称是 Cross Site Scripting,为了与“CSS”区分开来,故简称 XSS,翻译过来就是“跨站脚本”。XSS 攻击是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在
用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
可以将XSS分为三种:存储型XSS、反射型XSS以及基于dom的XSS。
存储型 XSS 攻击大致需要经过如下步骤:
1.首先黑客利用站点漏洞将一段恶意 JavaScript 代码提交到网站的数据库中;
2.然后用户向网站请求包含了恶意 JavaScript 脚本的页面;
3.当用户浏览该页面的时候,恶意脚本就会将用户的 Cookie 信息等数据上传到黑客服务器。

反射型XSS是指将可以script脚本插入用户请求的url中,当请求被服务器处理后又反射回给用户,web服务器并不会存储这段script脚本。

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

解决方案:

  • 服务器对输入脚本进行过滤或转码
    不管是反射型还是存储型 XSS 攻击,我们都可以在服务器端将一些关键的字符进行转码,比如最典型的:
code:<script>alert('你被 xss 攻击了')</script>
code:<script>alert('你被 xss 攻击了')</script>

这段代码过滤后,只留下了:

code
code

这样,当用户再次请求该页面时,由于script标签的内容都被过滤了,所以这段脚本在客户端是不可能被执行的。
除了过滤之外,服务器还可以对这些内容进行转码,还是上面那段代码,经过转码之后,效果如下所示:

code:&lt;script&gt;alert(&#39你被 xss 攻击了 &#39;)&lt;/script&gt;
code:&lt;script&gt;alert(&#39你被 xss 攻击了 &#39;)&lt;/script&gt;

经过转码之后的内容,如script标签被转换为<script>,因此即使这段脚本返回给页面,页面也不会执行这段脚本。

  • 充分利用 CSP
    csp又叫内容安全策略,可以把它看做是一个白名单,告诉浏览器哪些第三方资源可以执行。

  • 使用 HttpOnly 属性
    由于很多 XSS 攻击都是来盗用 Cookie 的,因此还可以通过使用 HttpOnly 属性来保护我们 Cookie 的安全。
    通常服务器可以将某些 Cookie 设置为 HttpOnly 标志,HttpOnly 是服务器通过 HTTP 响应头来设置的:

set-cookie: xxx;httpOnly;
set-cookie: xxx;httpOnly;

ClickJacking(点击劫持)

ClickJacking 翻译过来被称为点击劫持。一般会利用透明 iframe 覆盖原网页诱导用户进行某些操作达成目的。
解决方案:

  • 在HTTP投中加入 X-FRAME-OPTIONS 属性,此属性控制页面是否可被嵌入 iframe 中【DENY:不能被所有网站嵌套或加载;SAMEORIGIN:只能被同域网站嵌套或加载;ALLOW-FROM URL:可以被指定网站嵌套或加载。】

  • 判断当前网页是否被 iframe 嵌套(详情在第一条 firame 中)

HSTS(HTTP Strict Transport Security:HTTP严格传输安全)

网站接受从 HTTP 请求跳转到 HTTPS 请求的做法,例如我们输入“http://www.baidu.com”或“www.baidu.com”最终都会被302重定向到“https://www.baidu.com”。这就存在安全风险,当我们第一次通过 HTTP 或域名进行访问时,302重定向有可能会被劫持,篡改成一个恶意或钓鱼网站。
HSTS:通知浏览器此网站禁止使用 HTTP 方式加载,浏览器应该自动把所有尝试使用 HTTP 的请求自动替换为 HTTPS 进行请求。用户首次访问时并不受 HSTS 保护,因为第一次还未形成链接。我们可以通过 浏览器预置HSTS域名列表 或 将HSTS信息加入到域名系统记录中,来解决第一次访问的问题。

CDN劫持

出于性能考虑,前端应用通常会把一些静态资源存放到CDN(Content Delivery Networks)上面,例如 js 脚本和 style 文件。这么做可以显著提高前端应用的访问速度,但与此同时却也隐含了一个新的安全风险。如果攻击者劫持了CDN,或者对CDN中的资源进行了污染,攻击者可以肆意篡改我们的前端页面,对用户实施攻击。
现在的CDN以支持SRI为荣,script 和 link 标签有了新的属性 integrity,这个属性是为了防止校验资源完整性来判断是否被篡改。它通过 验证获取文件的哈希值是否和你提供的哈希值一样来判断资源是否被篡改。
使用 SRI 需要两个条件:一是要保证 资源同域 或开启跨域,二是在script标签中 提供签名 以供校验。

integrity 属性分为两个部分,第一部分是指定哈希值的生成算法(例:sha384),第二部分是经过编码的实际哈希值,两者之前用一个短横(-)来分隔。
这个属性也存在兼容问题