How to work-around firefox lack of respect for the CSP specification for CSP reports to Sentry

As stated in Firefox doesn't respect the specification and doesn't include the fields effective-directive or status-code.

Sentry expect them, and then refuse the reports because of that.

To workaround the issue, I used Nginx LUA module to manipulate the JSON body before it is send to the uwsgi backend of Sentry.

Note: use it at your own risks.

The CSP should contains:

Content-Security-Policy: whatever-you; want;... report-uri

Makes sures the module is enabled, on Debian it's something like:

# cat /etc/nginx/modules-enabled/00-mod-http-ndk.conf
load_module modules/;
# cat /etc/nginx/modules-enabled/50-mod-http-lua.conf
load_module modules/;
# Makes sure there is:
include /etc/nginx/modules-enabled/*.conf;
# before the http {} directive in /etc/nginx/nginx.conf

I also needed to do in /etc/nginx/nginx.conf because the paths seems wrong by default:

http {
	lua_package_path "/usr/share/lua/5.1/?.lua;;";
	lua_package_cpath '/usr/lib/x86_64-linux-gnu/lua/5.1/?.so;;';

Packages needed are:

nginx-extras libnginx-mod-http-lua libnginx-mod-http-ndk lua-cjson

Add LUA call in the virtual host of your Sentry:

	location ~ ^/api/(?<projet>[0-9]+)/csp-report/ {
		access_by_lua_file /etc/nginx/proxy_csp.lua;
		include uwsgi_params;

	location / {
		include uwsgi_params;

And the most usefull file:

if ngx.req.get_method() == "POST" then
    local cjson = require "cjson"
    -- read body and set local variables, also dump into logs for debugging if needed
    local body = ngx.req.get_body_data()
    --ngx.log(ngx.STDERR, body)
    -- read json body
    local json =
    -- We need to manipulate the JSON body to add if missing:
    -- effective-directive: the violated directive name
    -- status-code: HTTP status code of the violated directive
    if (not json['csp-report']['effective-directive']) then
	-- ugly split thing to get the directive name
    	words = {}
    	local vd = json['csp-report']['violated-directive']
    	for word in vd:gmatch("[a-zA-Z0-9-]+") do table.insert(words, word) end
    	if (words[1]) then
        	json['csp-report']['effective-directive'] = words[1]
        	json['csp-report']['effective-directive'] = 'Unknown violation wrong format string'
    if (not json['csp-report']['status-code']) then
    	json['csp-report']['status-code'] = 200
    -- reencode new body
    new_json = cjson.encode(json)
    -- set new body
    -- we are done