Skip to content

Instantly share code, notes, and snippets.

@keeth
Last active November 4, 2022 19:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keeth/d73b6b6491b9dc0339b3865de6addfbd to your computer and use it in GitHub Desktop.
Save keeth/d73b6b6491b9dc0339b3865de6addfbd to your computer and use it in GitHub Desktop.
CSP report rate-limiting proxy (cloud function)
const { createClient } = require("redis");
const fetch = require("node-fetch");
const REQUESTS_LIMIT = 1;
const TTL = 60; // seconds
const client = createClient({
url: process.env.REDIS_URL,
});
client.on("error", (err) => console.error("Redis error", err));
const HEADERS = ["content-type", "user-agent"];
const CONTENT_TYPES = new Set(["application/csp-report", "application/json"]);
async function sendReportToServer(report, opts) {
return await fetch(
process.env.UPSTREAM_SERVER_URL,
{
method: "POST",
body: JSON.stringify({ "csp-report": report }),
...opts,
}
);
}
exports.cspRateLimiter = async (req, res) => {
if (!client.isReady) {
await client.connect();
}
if (!CONTENT_TYPES.has(req.get("content-type"))) {
return res.status(400).send("Invalid content type");
}
const report =
req.body["csp-report"] || JSON.parse(req.body.toString())["csp-report"];
if (!report) {
return res.status(400).send("Missing csp-report");
}
const key = report["violated-directive"] + " " + report["blocked-uri"];
const count = await client.incr(key);
if (count === 1) {
await client.expire(key, TTL);
}
if (count > REQUESTS_LIMIT) {
return res.status(429).send("Too many requests!");
}
const response = await sendReportToServer(report, {
headers: HEADERS.reduce((acc, cur) => {
acc[cur] = req.get(cur);
return acc;
}, {}),
});
if (!response.ok) {
console.error("Upstream API error", response.status, response.statusText);
return res.status(500).send("Sentry error");
}
return res.status(204).send();
};
@keeth
Copy link
Author

keeth commented Nov 4, 2022

Google cloud function that proxies CSP reports to some other server, rate-limiting to 1 per (directive, blocked-uri) per minute.

Helps avoid flooding your CSP reporting tool with repetitive reports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment