You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

托管在Azure App Service的Angular应用如何添加Nonce支持实现合规CSP配置

纯Angular 12在Azure App Service实现带Nonce的严格CSP方案

方案一:基于IIS原生URL Rewrite模块实现(无需额外后端,适合Windows宿主)

Azure App Service Windows宿主默认预装IIS URL Rewrite模块,无需引入.NET Core技术栈即可实现Nonce全流程配置:

  • 第一步:修改Angular项目index.html
    删除原有CSP meta标签,所有需要授权的inline script(包括第三方脚本)统一添加nonce占位符,示例:
    <!-- 第三方inline script -->
    <script nonce="{{CSP_NONCE}}" src="第三方脚本地址"></script>
    <!-- 自有inline script如有需要也添加相同的nonce属性 -->
    
  • 第二步:在Angular项目根目录添加web.config文件,部署时同步到Azure App Service
    配置逻辑:每次请求生成随机Nonce,自动替换index.html中的占位符,同时注入标准CSP和仅报告模式CSP响应头,配置示例:
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <system.webServer>
        <rewrite>
          <allowedServerVariables>
            <add name="CSP_NONCE" />
          </allowedServerVariables>
          <rules>
            <!-- 生成随机Nonce存入服务器变量 -->
            <rule name="生成CSP Nonce" stopProcessing="false">
              <match url=".*" />
              <serverVariables>
                <set name="CSP_NONCE" value="{RANDOM}{RANDOM}{RANDOM}" />
              </serverVariables>
              <action type="None" />
            </rule>
            <!-- 保留Angular SPA默认路由重定向规则 -->
            <rule name="Angular SPA 路由" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
              </conditions>
              <action type="Rewrite" url="/" />
            </rule>
          </rules>
          <outboundRules>
            <!-- 替换HTML页面中的Nonce占位符 -->
            <rule name="替换页面Nonce占位符" preCondition="是HTML页面">
              <match filterByTags="None" pattern="{{CSP_NONCE}}" />
              <action type="Rewrite" value="{CSP_NONCE}" />
            </rule>
            <!-- 注入正式CSP响应头 -->
            <rule name="注入CSP响应头" preCondition="是HTML页面">
              <match serverVariable="RESPONSE_Content-Security-Policy" pattern=".*" />
              <action type="Rewrite" value="default-src 'self'; script-src 'nonce-{CSP_NONCE}' 'strict-dynamic' 替换为实际第三方域名; style-src 'self' 'unsafe-inline'; img-src 'self' data: 替换为实际第三方域名; font-src 'self'; connect-src 'self' 替换为实际接口域名; frame-src 'none'; object-src 'none'; base-uri 'self';" />
            </rule>
            <!-- 注入仅报告模式CSP响应头 -->
            <rule name="注入仅报告模式CSP响应头" preCondition="是HTML页面">
              <match serverVariable="RESPONSE_Content-Security-Policy-Report-Only" pattern=".*" />
              <action type="Rewrite" value="default-src 'self'; script-src 'nonce-{CSP_NONCE}' 'strict-dynamic' 替换为实际第三方域名; report-uri 替换为实际上报地址;" />
            </rule>
          </outboundRules>
          <preConditions>
            <preCondition name="是HTML页面">
              <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
            </preCondition>
          </preConditions>
        </rewrite>
        <staticContent>
          <mimeMap fileExtension=".json" mimeType="application/json" />
        </staticContent>
      </system.webServer>
    </configuration>
    

方案二:基于轻量Node.js伺服实现(适合Linux宿主)

如果使用Azure App Service Linux宿主,可以加入极简Express伺服层实现Nonce能力,无需修改Angular业务代码:

  • 第一步:项目根目录新增server.js文件
    const express = require('express');
    const crypto = require('crypto');
    const fs = require('fs');
    const path = require('path');
    const app = express();
    const PORT = process.env.PORT || 8080;
    
    // 静态资源直接返回
    app.use(express.static(path.join(__dirname, 'dist/替换为实际Angular构建产物目录名')));
    
    // 所有页面请求生成Nonce并注入
    app.get('*', (req, res) => {
      const nonce = crypto.randomBytes(16).toString('hex');
      const indexPath = path.join(__dirname, 'dist/替换为实际Angular构建产物目录名/index.html');
      let indexContent = fs.readFileSync(indexPath, 'utf8');
      // 替换页面中的Nonce占位符
      indexContent = indexContent.replace(/{{CSP_NONCE}}/g, nonce);
      // 注入正式CSP头
      res.setHeader(
        'Content-Security-Policy',
        `default-src 'self'; script-src 'nonce-${nonce}' 'strict-dynamic' 替换为实际第三方域名; style-src 'self' 'unsafe-inline'; img-src 'self' data: 替换为实际第三方域名;`
      );
      // 注入仅报告模式CSP头
      res.setHeader(
        'Content-Security-Policy-Report-Only',
        `default-src 'self'; script-src 'nonce-${nonce}' 'strict-dynamic' 替换为实际第三方域名; report-uri 替换为实际上报地址;`
      );
      res.send(indexContent);
    });
    
    app.listen(PORT, () => {
      console.log(`伺服启动,端口${PORT}`);
    });
    
  • 第二步:修改package.json的启动命令为node server.js,部署到Azure App Service Linux Node.js环境即可。

验证注意事项

  • 部署后可通过浏览器开发者工具「网络」面板查看页面响应头,确认两个CSP头都已正确注入,且nonce值和页面script标签的nonce属性完全一致
  • 不要使用固定Nonce,每次请求生成的Nonce唯一才具备XSS防护效果
  • 严格模式下无需添加unsafe-inline到script-src指令,符合安全要求

内容的提问来源于stack exchange,提问作者ickybyte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 00:15:03