Summary
As stated in this issue 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.
CSP Headers config
The CSP should contains:
Content-Security-Policy: whatever-you; want;... report-uri https://sentry.sigpipe.me/api/the_project_id/csp-report/?sentry_key=your_key&sentry_version=5
Nginx thing
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/ndk_http_module.so;
# cat /etc/nginx/modules-enabled/50-mod-http-lua.conf
load_module modules/ngx_http_lua_module.so;
# 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;
uwsgi_pass 127.0.0.1:9000;
}
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:9000;
}
...
And the most useful file, /etc/nginx/proxy_csp.lua
:
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
ngx.req.read_body()
local body = ngx.req.get_body_data()
--ngx.log(ngx.STDERR, body)
-- read json body
local json = cjson.new().decode(body)
-- 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]
else
json['csp-report']['effective-directive'] = 'Unknown violation wrong format string'
end
end
if (not json['csp-report']['status-code']) then
json['csp-report']['status-code'] = 200
end
-- reencode new body
new_json = cjson.encode(json)
-- set new body
ngx.req.set_body_data(new_json)
-- we are done
return
end
Comments
No comments yet. Be the first to react!