material-ui实现csp【含demo】

接React SSR实现,本文在此基础上去实现CSP安全策略,用于预防XSS攻击

四、material-ui实现CSP

4.1前提条件:

首先按照material-ui5官方案例让你的React项目已经完成了ssr(服务端)渲染

可以参见文章:https://blog.csdn.net/daisyboom/article/details/133866051?spm=1001.2014.3001.5501

4.2 开始实现

本人理解csp主要思路就是通过在CSP 标头中设置一个随机数nonce,限制所有的style文件、script脚本都必须携带正确的nonce值,才能允许访问对应的资源,同时该nonce在每次请求后都会发生变化,以此来防止XSS攻击!

下面按照上文提供的demo基础上,开始实现csp,要考虑的是:

  • 在server端中间件中生成的nonce该怎么传给client端?
  • 在client端中import './xxxx.css文件会形成一个

①第一步:按照官方示例:内容安全策略 (CSP) - 材料用户界面 (mui.com)

  • 在server端的中间件中生成nonce,并设置到res.locals.styleNonce中

    server.tsx

    import express from "express";
    import {v4} from "uuid";
    const app = express();
    app.use((req, res, next) => {
      // nonce should be base64 encoded
      res.locals.Nonce = Buffer.from(v4()).toString("base64");
      next();
    });
    
  • 设置csp标头

    server.tsx

    server.get("/", (req, res) => {
     //set http header csp
      res.setHeader("Content-Security-Policy-Report-Only",
        "default-src 'self'; style-src 'self' 'nonce-" + res.locals.Nonce +
        "'; script-src 'self' 'nonce-" + res.locals.Nonce + "'; report-uri http://localhost:5599/listen");
    });
    
  • 在每次请求时,将res.locals.styleNonce存储的新随机数nonce,发给设置的模板引擎中将nonce存储在window.NONCE_ID中

    • 我使用的是ejs模板引擎

    server.tsx

    server.get("/", (req, res) => {
     //set http header csp
      res.setHeader("Content-Security-Policy-Report-Only",
        "default-src 'self'; style-src 'self' 'nonce-" + res.locals.Nonce +
        "'; script-src 'self' 'nonce-" + res.locals.Nonce + "'; report-uri http://localhost:5599/listen");
    
      res.render("index", { html, css ,Nonce: res.locals.Nonce});
    });
    

    index.ejs

    • ejs中server端res.render发来的参数,用<%%>进行解析
    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>React-ssr-csp-material-ui</title>
        <%- css %>
      </head>
      <body>
        <div id="root"><%- html %></div>
        <script nonce="<%=styleNonce%>">window.NONCE_ID = "<%=styleNonce%>";</script>
        <script defer="defer" src="xxxxxxx.client.js"></script>
      </body>
    </html>
    
    
  • 在client端通过window[“NONCE_ID”],就可以获取到服务端设置的nonce值

    client.tsx

    const __webpack_nonce__ = window["NONCE_ID"];
    

②第二步:解决自行导入css文件,导致的报错

【存在问题】

  • 以下是因为在client端,自行引入的css文件,并没有设置随机数nonce,因而被拒绝

    在这里插入图片描述
    在这里插入图片描述

【解决方法】

  • 在server端创建create-nonce.js,放入以下代码

    • 注意/* global __webpack_nonce__ */不可以删除。否则文件编译报错
    • 它表示在该变量之后,导入的所有style/script标签,都会为其加上一个在window.NONCE_ID上设置的nonce值
    /* global __webpack_nonce__ */ // eslint-disable-line no-unused-vars
    __webpack_nonce__ = window.NONCE_ID; 
    
  • 在client端的client.tsx中导入create-nonce文件 注意:必须在.css文件之前导入!!

    import "../server/create-nonce";
    import "./index.css";//在client中导入的css文件
    
  • 再次运行可以看到

    4.3 Demo地址

    4.4 常见报错

    ①遇到内联地址报错的问题:

    方案一:可通过csp允许不安全的内联样式

      res.setHeader("Content-Security-Policy-Report-Only",
        "default-src 'self'; style-src 'unsafe-inline' " +
        "'; script-src 'self' 'nonce-" + res.locals.Nonce + "'; report-uri http://localhost:5599/listen");
    

    方案二:依次添加白名单,在unsafe-hashes后添加控制台报错的hash

      res.setHeader("Content-Security-Policy-Report-Only",
        "default-src 'self'; style-src 'self' 'nonce-" + res.locals.styleNonce +
        "' 'unsafe-hashes' 'sha256-fQ9khXcyZvQRWl/5riXDoZbI9F1nSP745q4aJkJvFXs='" +         
        "'; script-src 'self' 'nonce-" + res.locals.Nonce + "'; report-uri http://localhost:5599/listen");
    

    4.5 参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓六日

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值