I have an ASP.NET Core 6.0 Web API application with the below ExceptionHandlerMiddleware
:
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate next;
public ExceptionHandlerMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await this.next(context).ConfigureAwait(false);
}
catch (Exception ex)
{
await this.ConvertExceptionAsync(context, ex).ConfigureAwait(false);
}
}
private Task ConvertExceptionAsync(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var errorResponse = new ErrorResponse();
var result = string.Empty;
switch (exception)
{
case ValidationException validationException:
httpStatusCode = HttpStatusCode.BadRequest;
errorResponse.Error.Errors = JsonSerializer.Serialize(validationException.ValidationErrors);
break;
case BadRequestException badRequestException:
httpStatusCode = HttpStatusCode.BadRequest;
errorResponse.Error.Message = badRequestException.Message;
break;
case NotFoundException notFoundException:
httpStatusCode = HttpStatusCode.NotFound;
break;
case NotAcceptableException notAcceptableException:
httpStatusCode = HttpStatusCode.NotAcceptable;
errorResponse.Error.Message = notAcceptableException.Message;
break;
case Exception ex:
httpStatusCode = HttpStatusCode.BadRequest;
break;
}
errorResponse.ApiVersion = context.GetRequestedApiVersion()?.ToString();
errorResponse.Error.Code = (int)httpStatusCode;
context.Response.StatusCode = (int)httpStatusCode;
if (string.IsNullOrEmpty(result))
{
errorResponse.Error.Message = exception.Message;
}
var serializeOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
};
result = JsonSerializer.Serialize(errorResponse, serializeOptions);
return context.Response.WriteAsync(result);
}
}
It returns the error in the custom format like mentioned below
{
"error": {
"code": 404,
"message": "Education (a65f7f0c-2a29-4da0-bd4b-d737320730c6) is not found",
"errors": "[]"
},
"apiVersion": "1.0"
}
During the security scan, it is reported that
The file handles an Exception or runtime Error ex. During the exception handling code, the application exposes the exception details to WriteAsync, in method ConvertExceptionAsync
Avoid information leak through error messages
- Don’t expose users exception output data
- Properly handle exception for each methods
- Configure a global handler to prevent unhandled errors
Should I ask the security team to suppress this issue? Or this is something that can be addressed at the application level?
Update: As I just want to address the reported issue, "context.Response.WriteAsync" is moved to finally block. I hope it should address the above security issue.
public async Task InvokeAsync(HttpContext context)
{
bool isExceptionReported = false;
string result = string.Empty;
try
{
await this.next(context).ConfigureAwait(false);
}
catch (Exception ex)
{
isExceptionReported = true;
result = this.ConvertException(context, ex);
}
finally
{
if (isExceptionReported)
{
await context.Response.WriteAsync(result).ConfigureAwait(false);
}
}
}
private string ConvertException(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var errorResponse = new ErrorResponse();
var result = string.Empty;
switch (exception)
{
case ValidationException validationException:
httpStatusCode = HttpStatusCode.BadRequest;
errorResponse.Error.Errors = JsonSerializer.Serialize(validationException.ValidationErrors);
break;
case BadRequestException badRequestException:
httpStatusCode = HttpStatusCode.BadRequest;
errorResponse.Error.Message = badRequestException.Message;
break;
case NotFoundException notFoundException:
httpStatusCode = HttpStatusCode.NotFound;
break;
case NotAcceptableException notAcceptableException:
httpStatusCode = HttpStatusCode.NotAcceptable;
errorResponse.Error.Message = notAcceptableException.Message;
break;
case Exception ex:
httpStatusCode = HttpStatusCode.BadRequest;
break;
}
errorResponse.ApiVersion = context.GetRequestedApiVersion()?.ToString();
errorResponse.Error.Code = (int)httpStatusCode;
context.Response.StatusCode = (int)httpStatusCode;
if (string.IsNullOrEmpty(result))
{
errorResponse.Error.Message = exception.Message;
}
var serializeOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
};
result = JsonSerializer.Serialize(errorResponse, serializeOptions);
return result;
}