A simple example of a web request is demonstrated and what post processing is needed afterwards before logging it. Logging a full web request can cause a security problem but there is generic/reusable way to prevent that. The code that uses this way is shown.
Introduction
Security is really important these days. Privacy regulations are getting more severe, hackers are getting smarter and the value of data is increasing. In trainings and courses, developers are often told to use https and to use authentication. As a developer, there are other things you need to know as well. In this tip, one of these things is explained.
Background
It will be really helpful if you have a background in .NET development, preferably with .NET Core since that is the technology we use here. If you work with Xamarin or .NET Framework, this article is likely to be clear as well and useful for your daily work.
Using the Code
In the code shown here, a web request is sent to an external service. For the purpose of this article, it is not relevant what service that is. What is important is that some web request is done and that authorization is used.
static async Task Main()
{
using (var httpClient = new HttpClient(new SafeHandler()))
{
httpClient.BaseAddress = new Uri("https://www.google.com/");
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "DummyToken");
var response = await httpClient.GetAsync("");
Console.WriteLine($"Returned status code: {response.StatusCode}");
Console.WriteLine("END");
}
}
Logically, web requests are important, important events need to be logged and log output needs to be tested. If you want to know more about this, you may want to read this article. What we could do here is just add code that does the logging of the full request. However, this is not a good plan.
Logging needs to be done with data we need to be able to trace in case of a production issue. Logging should not be done with data only hackers want to know. That is exactly why the mentioned SafeHandler
was implemented before implementing the code above. Here is the code of the SafeHandler
. For demonstration purposes, we just use a serialize
method directly and log to the console. Most likely, you prefer a more advanced way of logging but that is out of scope for the purpose of this article. If you want to know more about advanced logging, read this article.
public class SafeHandler : DelegatingHandler
{
public SafeHandler()
{
InnerHandler = new HttpClientHandler();
}
protected override Task<HttpResponseMessage>
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var result = base.SendAsync(request, cancellationToken);
if (request.Headers.Authorization != null)
{
request.Headers.Authorization =
new AuthenticationHeaderValue(request.Headers.Authorization.Scheme, "***");
}
var toLog = JsonConvert.SerializeObject(request);
Console.WriteLine(toLog);
return result;
}
}
As it becomes clear from this code, the request is slightly modified after being sent. The actual value of the authorization header is replaced by asterisks. You will not be able to trace the value after logging but most likely, you do not need it to resolve a production problem. If there is a security issue in your logging, a hacker cannot trace it too and that is what counts. The data you want to replace by asterisks may be different but it is good to realize that this approach with a DelegatingHandler
can help you. No matter how and where you execute a web request, if you use the same HttpClient
with the same DelegatingHandler
, the code will be executed in all cases. If you want a working example directly, the code is on GitHub.
Points of Interest
Courses about security usually do not pay much attention to logging. Courses about logging usually do not pay much attention to security. When I saw something going wrong (seeing tokens in my logging), I started to realize that this gap needs to be closed which inspired me to write this article.
History
- 25th May, 2020: Initial version