wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Report your CSP (violations)


I'm a big fan of a strict Content Security Policy (CSP). It can be a pain to setup (but there is help, here, here, here and here) and evaluate.

Let's report it

You won't know if a policy was tried to be violated unless the attempt is reported back to your application. For that purpose we use the CSP directives report-to and the older, deprecated report-uri. Until Firefox catches up, use both. When a browser supports report-to, report-uri gets ignored.

Reporting isn't only useful in production, but already during development and especially during retrofitting. There you can swap the Content-Security-Policy header for Content-Security-Policy-Report-Only. It will allow all content to load, but report back all violations.

You then run your E2E Tests (You have those, haven't you?) and get a free overview what loads from where. Adjust the CSP, rinse and repeat.

Where to report to?

There are numerous SaaS providers with fancy dashboards, that offer ready made solutions. When you are pressed for time, that might be your best option. I haven't evaluated them, so I can't recommend or endorse them.

What I can do, is showing you server side code snippets, to integrate reporting into your application. A CSP violation report has the mime type application/reports+json and for the older format application/csp-report, we shall use this.

Vert.x

The Domino REST API got implemented using Vert.x, so this goes first.

public void cspReport(final Router router) {
  router.route("/csp-violation-report")
     .method(HttpMethod.POST)
     .consumes("application/csp-report",
               "application/reports+json")
     .handler(ctx -> {
        try {
          final JsonObject json = ctx.body().asJsonObject();
          // Do something with the log
          logCspViolation(json);
        } catch (Exception e) {
          // Add you loggin here
        }
        ctx.response().setStatusCode(204).end();
     });
}

Quarkus

Quarkus REST goes next.

@POST
@Path("/csp-violation-report")
@Consumes("application/csp-report","application/reports+json")
public void cspReport(final HttpServerResponse response, final JsonObject body) {
  // Do something with the log
  logCspViolation(body);
  response.setStatusCode(204).end();
}

ExpressJS

The popular NodeJS web framework ExpressJS next:

const setupCspReportRoute = (app) => {
  app.post('/csp-violation-report', express.json(), (req, res) => {
    logCspViolation(req.body);
    res.status(204).end();
  });
};

Rust / Rocket

It isn't done, until it has been rewritten in Rust, in this case using Rocket.

use rocket::{post, routes, serde::json::Json, http::Status};
use serde_json::Value;
use my_app::logCspViolation;

#[post("/csp-violation-report", format = "json", data = "<body>")]
fn csp_report(body: Json<Value>) -> Status {
    logCspViolation(&body);
    Status::NoContent
}

// To mount the route in your Rocket app:
rocket::build().mount("/", routes![csp_report]);

Rust / Axum

There are more options around in Rust, e.g. Axum

use axum::{routing::post, Json, Router, http::StatusCode};
use serde_json::Value;
use my_app::logCspViolation;

async fn csp_report(Json(body): Json<Value>) -> StatusCode {
    logCspViolation(&body);
    StatusCode::NO_CONTENT
}

// To mount the route in your Axum app:
let app = Router::new().route("/csp-violation-report", post(csp_report));

How do you handle CSP?

As usual YMMV


Posted by on 07 July 2025 | Comments (0) | categories: Java JavaScript Rust WebDevelopment

Comments

  1. No comments yet, be the first to comment