如何保证前端系统安全性

361 阅读11分钟

前言

随着互联网的高速发展,信息安全俨然成为行业最为关注的焦点之一。随着前端各种技术不断更新,前端的安全问题也值得我们重视。前端人员除了传统的 XSS、CSRF 等安全问题之外,还时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。下面说一下有哪些安全问题需要重视,以及如何去防护。

安全问题

  1. iframe风险
  2. opener
  3. XSS跨站脚本攻击
  4. CSRF攻击
  5. ClickJacking 点击劫持
  6. CDN劫持
  7. HSTS(HTTP Strict Transport Security:HTTP严格传输安全)
  8. 第三方依赖包带来的问题
  9. 本地存储数据泄露

问题描述及解决方案

iframe风险

前端页面需要用到第三方提供的页面组件,通常会以 iframe 的方式引入,比如广告插件等。这些第三方提供的插件可以运行 js 脚本、flash 插件等,破坏用户体验。

  1. 如何让自己的网站不被其他网站当作iframe引用?可加入以下代码,当发现我们的网站被其他网站引用时,可强制使网站跳转到其他网站。
if(top.location !== window.location){ top.location.href = xxx }
  1. 如何禁用,被使用的 iframe 对当前网站某些操作?

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

<iframe sandbox src="..."> ... </iframe>

参考:HTML sandbox 属性

  • allow-same-origin:允许被视为同源,即可操作父级DOM或cookie等
  • allow-top-navigation:允许当前iframe的引用网页通过url跳转链接或加载
  • allow-forms:允许表单提交
  • allow-scripts:允许执行脚本文件
  • allow-popups:允许浏览器打开新窗口进行跳转
    “”:设置为空时上面所有允许全部禁止

opener

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

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

* 这两种方式看起来没有问题,但是存在漏洞。 
* 通过这两种方式打开的页面可以使用 window.opener 来访问源页面的 window 对象。 
* 场景:A 页面通过 <a> 或 window.open 方式,打开 B 页面。但是 B 页面存在恶意代码如下: 
* window.opener.location.replace('https://www.baidu.com') 【此代码仅针对打开新标签有效】
* 此时,用户正在浏览新标签页,但是原来网站的标签页已经被导航到了百度页面。 
* 恶意网站可以伪造一个足以欺骗用户的页面,使得进行恶意破坏。 
* 即使在跨域状态下 opener 仍可以调用 location.replace 方法。

解决方案:

  • 当使用a标签跳转时
<a target="_blank" href="" rel="noopener noreferrer nofollow">a标签跳转url</a>

* 通过 rel 属性进行控制: noopener:会将 window.opener 置空,从而源标签页不会进行跳转(存在浏览器兼容问题) 
* noreferrer:兼容老浏览器/火狐。禁用HTTP头部Referer属性(后端方式)。 
* nofollow:SEO权重优化,详情见 https://blog.csdn.net/qq_33981438/article/details/80909881
  • 当使用window.open跳转时
<button onclick='openurl("http://www.baidu.com")'>click跳转</button>

function openurl(url) {
    var newTab = window.open();
    newTab.opener = null;
    newTab.location = url;
}

XSS(Cross-Site Scripting)跨站脚本攻击

定义:

XSS(Cross Site Scripting,跨站脚本),即攻击者往 Web 页面里嵌入恶意的客户端脚本,当用户浏览此网页时,脚本就会在用户的浏览器上执行,进而达到攻击者的目的。【获取用户的 Cookie、导航到恶意网站、携带木马】

解决方案

  1. 对输入和 URL 参数进行过滤,过滤掉会导致脚本执行的相关内容。
  2. 对动态输出到页面的内容进行 html 编码,使脚本无法在浏览器中执行。

CSRF (Cross-site request forgery) 跨站请求伪造

定义:

CSRF(Cross Site Request Forgery,跨站请求伪造),即在别的站点伪造了一个请求,在受害者访问一个网站时,其 cookie 还没有过期的情况下,攻击者伪造一个链接地址发送受害者并欺骗让其点击,从而形成 CSRF 攻击。

防御

  1. 验证 HTTP 的 Referer 字段。
  2. 在请求地址中添加 token 并验证。
  3. 在 HTTP 头中自定义属性并验证。
  4. 涉及到数据修改操作严格使用 post 请求而不是 get 请求。

get 的 URL 会被放在浏览器历史和 WEB 服务器日志里面,如果把关键数据放在 get 里面,被人偷窥了浏览器,会造成数据泄露。而 post 日志没有记录,也不会保留 URL,只要数据库服务器不被入侵,基本还是安全的。

ClickJacking 点击劫持

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

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

CDN劫持

什么是CDN?

        CDN又叫内容分发网络,主要是提高网站的速度,可以优化网站的访问速度,提高网站的安全性和稳定性。

        CDN能加速大家都知道,但其实,CDN本身是一种DNS劫持,只不过是良性的。不同于黑客强制DNS把域名解析到自己的钓鱼IP上,CDN则是让DNS主动配合,把域名解析到临近的服务器上。

        同时服务器开启了HTTP代理,让用户感觉不到CDN的存在。不过CDN劫持不像黑客那样贪心,劫持用户所有流量,它只“劫持”用户的静态资源访问,对于之前用户访问过的资源,CDN将直接从本地缓存里反馈给用户,因此速度有了很大的提升。

通过https加密可以防止CDN劫持

        把所有的内容加密起来,在传输过程中,任何劫持者都不能探测到实际传输交互的内容。自然也就能防止劫持了。

https防护优缺点

优点:防止劫持效果好,客户端逻辑变动小
缺点:技术成本高,尤其是CDN节点,协议变动较大,由http迁移到https。https握手时的非堆成加密性能损耗巨大。

除了可以通过https加密防劫持之外,用户也可以选择云防护。

HSTS

HSTS 是 HTTP 严格传输安全(HTTP Strict Transport Security) 的缩写。 这是一种网站用来声明他们只能使用安全连接(HTTPS)访问的方法。 如果一个网站声明了 HSTS 策略,浏览器必须拒绝所有的 HTTP 连接并阻止用户接受不安全的 SSL 证书。 目前大多数主流浏览器都支持 HSTS (只有一些移动浏览器无法使用它)。

用户首次访问时并不受 HSTS 保护,因为第一次还未形成链接。我们可以通过 浏览器预置HSTS域名列表 或 将HSTS信息加入到域名系统记录中,来解决第一次访问的问题。

第三方依赖包带来的问题

现在绝大多数的开发都是在借助开发框架和各种类库进行快速开发。这样做虽然方便快速,但是与此同时也存在安全风险,如果这些来自第三方的代码有安全漏洞,那么对应用整体的安全性依然会造成严峻的挑战。比如 Node.js 有一些已知的安全漏洞,比如 CVE-2017-11499,可能导致前端应用受到 DoS 攻击。

防御
使用 NSP(Node Security Platform)、Snyk 等等这类工具。

本地存储数据泄露

现在存储在前端也就是用户浏览器中的数据量逐渐增多。前端应用是完全暴露在用户以及攻击者面前的,在前端存储任何敏感、机密的数据,都会面临泄露的风险。

防御
加密,敏感信息不要存储在前端本地

防御措施总结

  1. 谨慎用户输入信息,进行输入检查(客户端和服务端同时检查)
  2. 在变量输出到HTML页面时,都应该进行编码或转义来预防XSS攻击
  3. 该用验证码的时候一定要添上
  4. 尽量在重要请求上添加Token参数,注意Token要足够随机,用足够安全的随机数生成算法
  5. 当有<object>时,合理设置X-Frame-Options HTTP响应头,添加sanbox属性等
  6. 检查验证请求来源,对每一个重要的操作都进行重新验证
  7. 不要将重要文件、备份文件存放在公众可以访问到的地方
  8. 安全防御的体系是相辅相成、缺一不可的

前端加密

目前前端主流的加密方案有:

  1. md5加密(不可逆)
  2. base64 加密
  3. res加密
  4. sha1加密(不可逆)
  5. 编码和解码字符串
  6. AES/DES加解密方式

md5加密(不可逆)

  • MD5 加密 是目前最安全有效的加密方式 因为它是单向不可逆
  • md5加密方式不是js内置的API, 需要使用插件实现MD5-github
  • md5是一种加密算法, 所有语言都可以使用不仅限于前端
  • 直接下载到本地 的用法 <script src="./md5.js"></script>
  • 加密可以嵌套 md5( md5(count) )

base64 加密

  • base64加密 是一种常见的加密方式,没有MD5安全 因为它是双向可解密
  • base64加密方式不是js内置的API, 需要使用插件实现
  • 也是所有语言都可以使用的加密算法
  • 直接下载到本地 的用法 <script src="./base64.js"></script>
  • cdn-base64下载 直接输入想要的第三方库 搜索就行
  • 加密可以嵌套 Base64.encode( Base64.encode(str1) )

res加密

现在比较安全且流行的加密方式是非对称加密(RSA)。其加密方式需要两个秘钥:私钥(私有秘钥)和公钥(公开秘钥)。公钥加密,私钥解密。

  • RSA 加密规则

公钥(publicKey)加密、私钥(privateKey)解密。不能逆向,私钥(privateKey)加密、公钥(publicKey)解密。说白了就是前后端都需要用公钥(publicKey)进行加密,用私钥(privateKey)进行解密。

  • 为啥不可逆呢?

前端代码的安全性差,是总所周知的。之所以称为私钥(privateKey),就是因为是私密的,不可公开的,需要确保 key 的安全。若前端私钥(privateKey)加密,就意味着需要将私钥放到前端保存,这是不安全的,也违背了确保数据安全的初衷。

  • RSA 双向加密解密

在开发过程中遇到这样一个问题:前端不光要加密数据传到后端,也需要将后端的传回来的加密数据解密。所以定义了两个方法,进行数据的加密解密。

sha1加密(不可逆)

sha1加密是一种不可逆的加密方式,将明文转换成一段散列值,将报文摘要加密后与明文一起传送给接受方,接受方将接受的明文产生新的报文摘要与发送方的发来报文摘要解密比较,比较结果一致表示明文未被改动,如果不一致表示明文已被篡改。

编码和解码字符串

这个主要是使用JS函数的escape()和unescape(),分别是编码和解码字符串。

escape采用ISO Latin字符集对指定的字符串进行编码。所有的空格符、标点符号、特殊字符以及其他非ASCII字符都将被转化成%xx格式的字符编码(xx等于该字符在字符集表里面的编码的16进制数字)

AES/DES加解密方式

  • 下载crypto-js.js 引入使用 网址:引入地址
  • 注:加密的时候必须转成字符串 使用toString。 解密的时候 必须使用utf8的格式

TDH_Pro前端安全及加密处理

1、内网防止被当作ifram嵌套
2、所有node_module包都进行security过审
3、前端session进行加密保存
4quasar文档站中告诉我们哪些是安全的,哪些是非安全的
(https://quasar.dev/security/dos-and-donts)