【问题标题】:Can't parser content of the CSP report无法解析 CSP 报告的内容
【发布时间】:2021-09-21 09:23:49
【问题描述】:

我正在通过report-to 指令发送 CSP 报告:

app.use(express.json({
    type: [
        "application/json",
        "application/csp-report",
        "application/reports+json"
    ]
}));

const _reportCSP = {
    endpoints: [
        {
            url: "https://myapp.com/reportCSP"
        }
    ],
    group: "csp-endpoint",
    include_subdomains: true,
    max_age: 31536000
};

res.setHeader("content-security-policy", `default-src 'none'; script-src https://*.someHost.com 'self' 'unsafe-eval' 'unsafe-inline'; style-src https://*.someHost.com 'self'; font-src https://*.someHost.com 'self'; img-src 'self'; connect-src https://*.someHost.com https://*.dropboxapi.co 'self'; frame-ancestors 'none'; report-to ${reportCSP.group};`);

res.setHeader("report-to", JSON.stringify(reportCSP));

URL https://*.dropboxapi.co 仅用于 CSP 报告测试目的。

基于this 示例,我按以下方式处理 CSP 报告请求:

function echoReports(request, response) {

    for (const report of request.body) {
        console.log(`Report content: ${report}`);
        console.log(`Report content: ${JSON.stringify(report)}`);
    }
}

app.post("/reportCSP",

    async (req, res) => {

        console.log(`${req.body.length} CSP violation reports:`);

        echoReports(req, res);
    }
);

结果,我进入了服务器端:

1 CSP violation reports:
Report content: [object Object]
Report content: "[object Object]"

在 DevTools 中我看到了正确的错误报告:

Refused to connect to 'https://content.dropboxapi.com/…' because it violates the following Content Security Policy directive: "connect-src https://*.someHost.com https://*.dropboxapi.co 'self'"

Refused to connect to 'https://content.dropboxapi.com/…' because it violates the document's Content Security Policy.

JSON.stringify(request) 内部的echoReports(req, res) 导致:

TypeError: Converting circular structure to JSON
     --> starting at object with constructor 'Socket'
     |     property 'parser' -> object with constructor 'HTTPParser'
     --- property 'socket' closes the circle
     at JSON.stringify (<anonymous>)
     at echoReports (file:///app/src/server/app.mjs:2949:33)

由于我使用的是 Express.js 4.17.1,因此我不使用 body-parser,而是使用 express.json(…)

我尝试了几种方法在服务器端打印 CSP 报告的内容,但没有成功。

当然,任何反横幅、安全和隐私保护软件都已停用。

附:我已经详细阐述了这个问题,以便更清楚地说明我要解决的问题是什么。

【问题讨论】:

  • 你的connect-src 指令的值没有错字吗? https://*.dropboxapi.co 不应该是 https://*.dropboxapi.com 吗?
  • @jub0bs,打错字是检查 CSP report-to,一旦我弄清楚如何获取报告,我会修复它。
  • ${policyViolationReport.group} 计算结果为 "policyViolationReport",而不是 "/policyViolationReport"report-to ${policyViolationReport.group} 中的前导斜杠应该来自哪里?
  • 我假设${policyViolationReport.group} 引用group: "policyViolationReport",这意味着${policyViolationReport.group} = "policyViolationReport"。该组应该以/ 开头吗?
  • 我不知道组应该是什么,但是report-to指令的值绝对不应该是policyViolationReport。尝试在 CSP 标头中硬编码/policyViolationReport,看看是否有任何改变。

标签: content-security-policy


【解决方案1】:
  1. 检查浏览器是否接收到Report-To HTTP 头,引导是here

  2. 使用chrome://net-export/https://netlog-viewer.appspot.com 工具检查网络日志:

  • 对于最新的 Chrome 版本,请在单独的选项卡上打开 chrome://net-export 页面并启用将网络日志记录到磁盘。
  • 使用发布Report-To 标头的页面重新加载选项卡。
  • 使用chrome://net-export 页面上的&lt;Stop logging&gt; 按钮停止将网络日志记录到磁盘。
  • 在单独的选项卡上打开 https://netlog-viewer.appspot.com 日志查看器,然后选择您的日志文件。
  • 在左侧菜单中选择“报告”,然后在“队列报告”部分中,单击“显示原始报告”链接。如果所有报告都已发送,您将看到 CSP 报告已创建并排队或为空。
    还可以查看“Per-origin config”表的底部: 在“上传”列中,将显示已发送报告的数量。

完整的分步指南是here

  1. 发布Report-To 标头的页面本身必须使用 HTTPS: 加载,否则将不会发送报告。 Endpoint 的 Url 也应该是 HTTPS:

  2. 请注意,如果您的站点在 Cloudflare 后面运行,Report-To 标头将不起作用。

更新

好像这段代码sn-p:

app.post("/policyViolationReport",

    async (req) => {
        console.log("Bingo! CSP Report occurred.");
    });

将不会收到违规报告,因为违规报告不是作为普通 POST 数据发送的(即&amp;param=value)。浏览器只发送 JSON 正文。

尝试使用这个:

app.use(
    bodyParser.json({
        type: ['application/json', 'application/csp-report', 'application/reports+json'],
    })
);
    
app.post('/policyViolationReport', (req, res) => {
    console.log(req.body);
    res.status(204).end();
});

【讨论】:

  • 看起来您只是在服务器端错误地处理 CSP 报告。请参阅答案的更新部分。
  • 根据this的文章,我已经成功想出了实现后端的方法。唯一的问题是,当我尝试迭代 req.body 时,我得到了 report.body: undefined。我需要找出为什么在req.body 的迭代过程中我得到undefined
  • request 是一个数组,因此您必须遍历此数组,但不能遍历不存在的 request.body。试试for (const report of request) { console.log(report.body); } - 将为数组的每个元素定义report.body
  • 检查您在报告中真正得到了什么:console.table( JSON.stringify( request ) )。此外bodyParser() 提供对请求的RAW data 的访问,但您不使用外部body-parser 中间件,您使用的是Express 内置的body 解析器。在这种情况下,我不知道如何访问 RAW 数据。
  • Here 你可以检查你的浏览器是否支持report-to 指令。 report-to 尚未在 Chrome 中开发,它已经支持它 3 年或更长时间。但是 Firefox/Safari 仍然没有实现它。
猜你喜欢
  • 2012-10-07
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-07
  • 1970-01-01
  • 2015-01-27
  • 1970-01-01
相关资源
最近更新 更多