首页 > 解决方案 > Can't parser content of the CSP report

问题描述

I'm sending a CSP-report via report-to directive:

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

An URL https://*.dropboxapi.co is used for the CSP-reports testing purposes only.

Based on this sample, I handle a CSP-report request in the following manner:

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

As a result, I get on a server-side:

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

In DevTools I see the correct error report:

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) inside of echoReports(req, res) leads to:

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)

Since I'm on Express.js 4.17.1, I don't use body-parser but use express.json(…) instead.

I've tried several approaches to print a content of the CSP-report on the server-side but no success.

Of course, any anti-banner, security and privacy protection software had been deactivated.

P.S. I've elaborated the question to make it more clear what's the problem I'm trying to solve.

标签: content-security-policy

解决方案


  1. Check that the browser receives the Report-To HTTP header, the guide is here.

  2. Check network log using the chrome://net-export/ and https://netlog-viewer.appspot.com tools:

  • For latest Chrome versions open the chrome://net-export page on a separate tab and enable recording of network log to disk.
  • Reload the tab with the page which publishes the Report-To header.
  • Stop recording of network log to disk with the <Stop logging> button at the chrome://net-export page.
  • Open the https://netlog-viewer.appspot.com log viewer on a separate tab, and select the file of your log.
  • Select "Reports" in the left menu, and in the "Queued reports" section, click on the link "Show raw report". You'll see CSP reports created and queued or empty section if all reports have been sent.
    Also have a look at the bottom of the "Per-origin config" table: Per-origin config table In the "Uploads" column the number of sent reports will be indicated.

A complete step-by-step guide is here

  1. The page itself that publishes a Report-To header must be loaded with HTTPS:, otherwise reports will not be sent. Endpoint's Url should be HTTPS: too.

  2. Note if you site works behind Cloudflare, the Report-To header will not work property.

update

It seems that this code snippet:

app.post("/policyViolationReport",

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

will not receive violation reports because violation reports are not sended as an ordinary POST data (i.e. &param=value). Browser sends just body of JSON.

Try to use this:

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

推荐阅读