I'm trying to set up CSP in an asp.net core webapp, and the CSP part works fine, I can see the violations in the browser console as they are sent to the report-uri endpoint.
However, I cannot seem to create the correct method in a controller to receive these messages!
I create a method in the controller as:
[HttpPost]
[AllowAnonymous]
public IActionResult UriReport(CspReportRequest request)
{
_log.LogError("CSP violation: " + request);
return Ok();
}
and it will be called, but the 'request' parameter is always null. Some searching reveals that I need to use the [FromBody] attribute to read the data from the body, but once I put that in, it no longer gets called. (CspReportRequest is a class with properties matching the csp-report payload, but it doesn't work with string type either.)
So further reading suggests I add a handler for the 'application/csp-report' content-type that the body is being sent as:
services.Configure<MvcOptions>(options => {
options.InputFormatters.OfType<JsonInputFormatter>().First().SupportedMediaTypes.Add(
new MediaTypeHeaderValue("application/csp-report"));
});
But this doesn't seem to make a difference.
So - how do I make the correct controller signature, and/or the correct service handler options to receive the data.
There are two things required to make this work. The first is adding [FromBody]
to your CspReportRequest request
parameter1:
public IActionResult UriReport([FromBody] CspReportRequest request)
Without [FromBody]
, the JsonInputFormatter
will not be used to parse the request body. However, with [FromBody]
, you're going to start seeing 415
responses.
The second thing is configuring the JsonInputFormatter
to support the application/csp-report
media-type, which you've already attempted to do. The problem with your approach is that there are actually two instances of JsonInputFormatter
configured, and you're affecting the wrong one. If you just change from First()
to Last()
2, it should work.
Why? The first JsonInputFormatter
in the collection is actually an instance of JsonPatchInputFormatter
, which extends JsonInputFormatter
:
public class JsonPatchInputFormatter : JsonInputFormatter
This gets added first and so it's the one you're configuring. It can't process an instance of CspReportRequest
because it has specific rules about handling JsonPatchDocument<T>
, etc, so it passes on to the second JsonInputFormatter
. This second instance isn't configured to support application/csp-report
, as I've mentioned, so it also can't handle the request.
1 If you're using [ApiController]
, you won't need to use [FromBody]
, but everything from your question suggests that you're not using [ApiController]
.
2 Using Last()
instead of First()
isn't necessarily the best approach here, but it should demonstrate where the problem lies. There are many ways to get the specific JsonInputFormatter
you are interested in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With