无法解析 CSP 报告的内容

Can't parser content of the CSP report

我正在通过 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 报告的内容,但都没有成功。

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

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

  1. 检查浏览器是否收到Report-To HTTPheader,引导为here.

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

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

完整的 step-by-step 指南是 here

  1. 发布 Report-To header 的页面本身必须使用 HTTPS: 加载,否则将无法发送报告。端点的 Url 也应该是 HTTPS:。

  2. 请注意,如果您的站点支持 Cloudflare,则 Report-To header 将不起作用 属性。

更新

似乎是这段代码:

app.post("/policyViolationReport",

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

不会收到违规报告,因为违规报告不会作为普通 POST 数据发送(即 &param=value)。浏览器仅发送 JSON 个中的 body 个。

尝试使用这个:

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();
});