I have an API written in .NET Core 2.0 for dispensing JSON Web Tokens (JWTs). This is done via a POST request with a very simple model.
public class TokenRequest
{
public string Username { get; set; }
public string Password { get; set; }
}
The particulars of the API aren't important -- the goal here is to prevent the password from remaining in memory after the request is complete. Let's assume I can handle the string securely once it's in -- the problem I'm trying to solve is preventing Json.NET from assigning the value to a string and thus causing it to be interned.
EDIT: As pointed out in an answer the string is not interned here, which was my mistake. Even so, my concern is that the password could hang around in memory for a long time in a way that I can't control (a string) rather than a way I can control (a byte array, which I could zero out when I'm finished with it). I've removed further references to interning for clarity.
To test, I've been making requests and using WinDbg to determine if the values are in memory as strings.
My original model won't work as-is because it uses string
-- even if nothing in my code references Password
, just the fact that it's deserialized ends up putting the string in process memory until it's garbage collected.
Knowing that, I tried this model:
public class TokenRequest
{
public string Username { get; set; }
public byte[] Password { get; set; }
}
This actually works -- but the problem is that Password
now must be a base64 encoded string. I couldn't find either the original base64 value or the decoded value in memory as a string, which was good, but having the password base64 encoded is undesirable.
I've looked at the source code of JsonTextReader
and it makes sense why this works -- ReadAsBytes
reads using char arrays and byte arrays, never strings. But unfortunately the base64 requirement is hard-coded in.
EDIT: Upon further consideration, the passwords are possibly still present in memory as byte arrays that haven't been GCed -- byte arrays I have no control over because they're internal to Json.NET
So, I tried a custom JsonConverter instead:
public class TokenRequest
{
public string Username { get; set; }
[JsonConverter(typeof(ByteConverter))]
public byte[] Password { get; set; }
}
This suffers the same problem as the original -- Json.NET ends up sending the value through a string when parsing it for the converter, so even when the ReadJson
method of my converter was nothing more than return new byte[] { };
, the value could still be found in memory.
Summary
I'd like to get a plaintext string value into .NET Core WebAPI, and remove it from memory once the request is complete, without having to wait for garbage collection.
What kind of works, but is undesirable
- Using
byte[]
(with the caveat it must be base64 encoded)
What doesn't work
- Using any type of
JsonConverter
(Json.NET internally uses strings) - Using Ngen in any capacity (it might work, but it's not an option)