前端安全防护

933 阅读9分钟

安全技能1:不要滥用Storage,应将 Token 添加到cookie 并且做httponly、samesite、secure限制

  • 场景复现:今天试了一下,在Chrome和Firefox打开自家项目网站,先Chrome登录后,将其sessionStorage的所有数据,复制一遍,放到Firefox上的

  • 结果:刷新一遍无需登录也能进入网站(诸位也可以试试自家网站)

  • 危险性漏洞:当有人使用跨站脚本攻击获取到你的本地缓存数据后,那么无需账密也能进入你的网站

  • 分析:这是因为token等登陆状态信息都放在了会话存储中

  • 解决方案:

    • 因为本地缓存localStorage或sessionStorage,都没有加密或限制功能,都能用js脚本随意获取到storage数据,进而存在一旦被跨站脚本攻击成功则GG。
    • 而客户端数据存储方案,还有cookie技术,且cookie正有限制选项功能,能够限制是否能够被读取。
    • 当然,前端只需要配置Credentials即可,无需去操作cookie,后端发送过来的响应头的Set-Cookie,将会在下一次HTTP请求头的Cookie自动一起发送过去。
      • cookie主要配置项:
        • httpOnly: true/false;
          • 设置了 HttpOnly 属性为true的 cookie,将不能使用 JavaScript 经由 Document.cookie 属性、XMLHttpRequest 和 Request APIs 进行访问,以防范跨站脚本攻击。
        • secure: true/false;
          • 一个带有 secure 安全属性的 cookie, 只有在请求使用SSL和HTTPS协议的时候才会被发送到服务器。
        • sameSite: None/Strict/Lax;
          • SameSite属性用来限制第三方 Cookie,使cookie不能随着跨域请求一起发送,从而防范跨站请求伪造攻击(CSRF),减少安全风险。
          • 注意: 如果sameSite属性值为None,则cookie的secure必须为true,否则将会遭到客户端的Block拒绝,无法写入cookie

    image.png image.png

  • 延伸知识:XSS & CSRF

    • XSS跨站脚本攻击盗取用户信息手段
      • 非持久型 XSS 漏洞攻击
        • 通过 URL (类似:https://xxx.com/xxx?default=<script>alert(sessionStorage)</script>) 注入可执行的脚本代码,从而盗取数据
      • 持久型 XSS 漏洞攻击
        • Form 表单提交,将内容提交进入数据库保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行,比如类似在文本域或富文本输入<script>alert(sessionStorage)</script>

      防御以上这两种XSS攻击,一般是转义字符,或设置CSP白名单

    • CSRF:跨站请求伪造
      • 完成 CSRF 攻击的三个条件:
        1. 用户已经登录了站点 A,并在本地记录了 cookie
        2. 在用户没有登出站点 A 的情况下(也就是 cookie 生效的情况下),访问了恶意攻击者提供的引诱危险站点 B (B 站点要求访问站点A)。
        3. 站点 A 没有做任何 CSRF 防御

      防御CSRF:Cookie SameSiteReferer CheckAnti CSRF Token验证码

安全技能2:代码混淆压缩:

安全技能3:JS签名规则加密

  • 场景案例参考:再解决不了前端加密我就吃shi

    • 亲测了一遍这位狠人的方法,虽然该Tmall网站的加密规则及字段参数已有所改变,但获取流程依然不变,debug拿到加密规则rsaPassword和Local.e,便能获得password2值
  • 问题:既然能被破解,要你加密何用?

    • 虽然前端经过混淆和压缩,以及函数加密,依然无法彻底有效保护代码,但能提高攻击者进行攻击的难度,使之增加攻击者成本,而不是直接爬取js脚本后就能一眼得知加密规则,那么我们的防护目的也就达到了
  • JS签名规则加密

    虽然前端经过混淆和压缩,但如前文案例,依然可被debug一步步查找后拿到签名的相应生成规则。
    所以,为了给攻击者添堵,使攻击者看到的是“一堆乱码”,看不出任何实际的内容,将签名规则函数进一步加密是很有必要的防护手段!

    • 加密方式:一种或多种一起使用(前后端保持一致加密规则对比各自签名是否一致)
      1. base64:window.btoa / window.atob
      2. md5: hex_md5 / b64_md5 / str_md5 (加密不可逆)
      3. sha1 (加密不可逆)
      4. escape
      5. AES
      6. ……
    • 其他加密方式: jsEncrypto 加密脚本工具

      借助该工具,自己再进行调整使之适用自己当前的项目,使代码得到更深度的加密,甚至我们可以将整个脚本进行加密,如果你为了安全性完全不考虑服务器带宽压力的话。

      • 示例:
        • 未加密前的sign规则函数:
          function sign(obj, util, md5, APP_SECRET) {
             let str = util.addStr(util.objKeySort(obj));
             str = encodeURIComponent(str);
             str = str.replace(/\'/g, "%27");
             str = str.replace(/\!/g, "%21");
             str = str.replace(/\*/g, "%2A");
             str = str.replace(/@/g, "%40");
             str = str.replace(/\(/g, "%28");
             str = str.replace(/\)/g, "%29");
             str = APP_SECRET + str.toUpperCase() + APP_SECRET;
             str = md5.hex_md5(str);
             return str;
          }
          
        • 加密后的sign规则函数:
          let dF = new Function('return '+ unescape('%66%75%6E%63%74%69%6F%6E%20%64%46%28%73%29%7B%76%61%72%20%73%31%3D%75%6E%65%73%63%61%70%65%28%73%2E%73%75%62%73%74%72%28%30%2C%73%2E%6C%65%6E%67%74%68%2D%31%29%29%3B%20%76%61%72%20%74%3D%27%27%3B%66%6F%72%28%6C%65%74%20%69%3D%30%3B%69%3C%73%31%2E%6C%65%6E%67%74%68%3B%69%2B%2B%29%74%2B%3D%53%74%72%69%6E%67%2E%66%72%6F%6D%43%68%61%72%43%6F%64%65%28%73%31%2E%63%68%61%72%43%6F%64%65%41%74%28%69%29%2D%73%2E%73%75%62%73%74%72%28%73%2E%6C%65%6E%67%74%68%2D%31%2C%31%29%29%3B%72%65%74%75%72%6E%28%75%6E%65%73%63%61%70%65%28%74%29%29%3B%7D'))()
          let sign = new Function('return '+ dF('kzshynts*75xnls*7%3Dtgo*7H*75zynq*7H*75ri%3A*7H*75FUUdXJHWJY*7%3E*75*%3CG*5F*75*75qjy*75xyw*75*8I*75zynq3fiiXyw*7%3Dzynq3tgoPj%7EXtwy*7%3Dtgo*7%3E*7%3E*8G*5F*75*75xyw*75*8I*75jshtijZWNHtrutsjsy*7%3Dxyw*7%3E*8G*5F*75*75xyw*75*8I*75xyw3wjuqfhj*7%3D4*%3AH*7%3C4l*7H*75*77*7%3A7%3C*77*7%3E*8G*5F*75*75xyw*75*8I*75xyw3wjuqfhj*7%3D4*%3AH*764l*7H*75*77*7%3A76*77*7%3E*8G*5F*75*75xyw*75*8I*75xyw3wjuqfhj*7%3D4*%3AH/4l*7H*75*77*7%3A7F*77*7%3E*8G*5F*75*75xyw*75*8I*75xyw3wjuqfhj*7%3D4E4l*7H*75*77*7%3A95*77*7%3E*8G*5F*75*75xyw*75*8I*75xyw3wjuqfhj*7%3D4*%3AH*7%3D4l*7H*75*77*7%3A7%3D*77*7%3E*8G*5F*75*75xyw*75*8I*75xyw3wjuqfhj*7%3D4*%3AH*7%3E4l*7H*75*77*7%3A7%3E*77*7%3E*8G*5F*75*75xyw*75*8I*75FUUdXJHWJY*750*75xyw3ytZuujwHfxj*7%3D*7%3E*750*75FUUdXJHWJY*8G*5F*75*75xyw*75*8I*75ri%3A3mj%7Ddri%3A*7%3Dxyw*7%3E*8G*5F*75*75wjyzws*75xyw*8G*5F*%3CI5'))()
          
  • 延伸:Token、Sing与加密的作用

    • Token的作用:
      • 判断用户身份的标识
    • 签名Sign的作用:
      • 保证API接口通信时数据的安全性,进行数据校验是否有不安全的字段提交,防止信息被篡改和伪造
    • 加密的作用:
      • 将数据或代码加密,使明文变成暗文,让攻击者看不出任何实际的内容

代码漏洞扫描优化

安全尚无银弹,狼人依旧猖狂

  • Vue 安全

  • NPM第三方依赖的安全隐患

    node依赖安全扫描工具 参考文档

    • npm@6.0新特性:npm audit
      1. npm audit需要当前项目存在package.jsonpackage-lock.json文件。
        • 如果没有这两个文件,将会报相应EAUDITNOPJSONEAUDITNOLOCK错误提示
        • 生成package.json文件: npm init
        • 生成package-lock.json文件: npm i --package-lock-only
      2. npm audit相关命令
        1. npm audit [--json | --parseable] : 默认输出table格式,--json输出json格式,--parseable输出纯文本格式

          • 如下图第一行:

            • Severity: 有四个等级:critical(立即处理), High(尽快处理), Moderate(有时间就处理), Low(自行决定要不要处理)
            • Description:漏洞的描述
          • Package: 哪个包有问题

          • Patched in: 打补丁,哪些版本可修复漏洞的版本范围

          • Dependency of: 你的项目中哪个包依赖了这个有问题的包

          • Path: 项目中的这个包到有问题的包之间的依赖路径

          • More info: 安全报告的链接, 查看这个问题的更多详细信息 image.png

          • npm audit 官方文档:about-audit-reports

          • npm audit 官方文档:Auditing package dependencies

          注意1:npm audit命令在 npm@6 中可用。要升级,请运行npm install npm@latest -g.
          注意2: npm audit检查内容包含直接依赖项、devDependencies、bundledDependencies 和 optionalDependencies,但不检查 peerDependencies.

          注意3: npm audit命令在淘宝镜像不支持使用,必须是npm初始源https://registry.npmjs.org/.
          image.png

        2. npm audit fix

          • npm aduit [fix] 扫描并会自动更新到semver兼容的版本来消除漏洞
        3. npm audit fix --force

          • --force强制更新到安全版本, 即使semantic versioning不兼容也会更新
          • 但不一定能帮你修复所有的漏洞,有些需要手动去根据audit提示进行安装或卸载相应依赖
          • 有时修复后的依赖包不符合当前项目,导致运行崩溃,所以切记修复前做好备份,以便回滚

        注意: npm audit fix [--force]强制修复后,记得重新npm i加载依赖,再重新运行项目npm run dev,避免因为依赖丢失而导致项目报错无法运行

    • npm相关命令:
      • 查看当前npm源: npm config get registry
      • 配置npm源:
        • 原始镜像:npm config set registry https://registry.npmjs.org

        • 淘宝镜像:npm config set registry https://registry.npm.taobao.org