Content-Security-Policy: ...; report-uri https://e1x3a6m8p4le.execute-api.us-east-1.amazonaws.com/latest;
So what does this report-uri does exactly — Well it specifies an uri (absolute or relative), which accepts a json data over a POST endpoint.
The api can be part of the website code, or setup on a different server. In case the endpoint is under the domain as the website, it can be used as a relative path in your CSP report-uri directive, otherwise an absolute path is needed.
It makes sense to keep this api away from the server where the website is hosted, as any unintentional super restrictive CSP header can send back lots of violation report, and depending on server’s usual traffic it can have multiplicative effect by the factor of N no of violations per Visitor per Page.
That’s why AWS serverless seems perfect for this task. It doesn’t require a whole new server for just one endpoint and the best part is that it can auto scale as per traffic. So lets see how can we set this up on AWS.
To bring it up, we shall be touching these 4 aws services.
- API Gateway
- IAM (to enable above services to talk to each other)
There are multiple ways of creating resources on aws. This article will show the easiest way: aws console, and sometimes later on I will put up a link here for a tutorial on doing the same thing in cloudformation.
Lets start with creating a dynamodb table. The name of the table can be anything. We will need this name later in our lambda function.
Table name : cspdata
Primary key: id, string
Before we create the lambda function, it needs to be allowed to access dynamodb. To do this an IAM role is needed, with a policy specifying full access on our dynamo db table.
Role Name: cspdata-lambda-role
Paste below policy in policy JSON editor.
Make sure you replace the Account Id, with your own aws account id.
Review and save the policy. The lambda function must use this role in order to access the dynamo db. Do note the wildcard (csp*) in Resource entity above, used to access all tables whose name starts with csp. We can set this to exact table name as well, instead of wildcard.
Time to write the lambda function. This function reads the csp report from the request json and writes the data to the dynamodb.
Lambda name: cspdata-lambda
Runtime : NodeJs 8.10
Role : existing, cspdata-lambda-role
Make sure correct role is selected, while creating the function.
A quick summary of above code:
For every request, if its a POST request, then first replace any empty field values with ‘NA’, check the json body contains ‘csp-report’ in it or not, if yes, then grab the value of ‘csp-report’, append a uuid and timestamp to it and save it in dynamodb and for any non POST request, return error.
In environment variable add a key-value for table.
table : cspdata
Now we need to add a API gateway to create our post endpoint, which on invoke, will call this lambda function.
Create a new rest API Gateway with below details.
Add a method in that API. In this case it will be a POST endpoint.
Setup the POST endpoint. We need to integrate this endpoint with our lambda function.
Integration type : Lambda Function
User Proxy : yes
Lambda Function : cspdata-lambda
We also need to setup method ANY and set it to a MOCK. The intention is just to allow POST endpoint and any other endpoint should return 405 Not Allowed.
Update the Method Response and change it to 405 as default. Delete the 200 response and create a new response for 405.
Now go to Integration Response and add a response for 405 status. Delete the 200 response there as well.
After save, expand the newly added 405 response and a mapping template to return empty json along with 405 status.
As a final step, we need to deploy this api. Go to actions and click Deploy API.
Deploy api with these details.
Deployment stage : [New Stage]
Stage name : latest
Once deployed, you will get this nice api endpoint.
Well… not that nice looking url, but it is good enough to be used for CSP report-uri. We can however setup our own custom url, something like like https://example.com/csp . That can be done using Customs Domain Names, in API Gateway, by assigning a base path to the api. I will leave it out of the scope of this tutorial, to keep things simple.
Time to tests the csp report api. I am using postman for testing.
Sample violation report source: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP#Sample_violation_report
Verify the entry in the DynamoDB table.
That’s it. Our API works great and is now ready to be used in CSP report-uri.
We just created our csp report uri through aws console. I will put up a link here for the tutorial on creating the same api using cloudformation very soon. Do let me know if you have any question. Have a great time.