Mvc: HTTP request input strings stored on heap

Created on 23 Jan 2017  路  11Comments  路  Source: aspnet/Mvc

So I think this actually belongs on the ASP.NET core discussion, but since MVC model binding is the most common use case, and the solution would likely require end-to-end modification, I'm discussing it here:

Input coming over HTTP (and even HTTPS) and surfaced via the Request object are converted to string or IEnumerable which results in plain-text storage on the heap; minimizing the time such data lives on the heap should be a goal of any framework that takes security seriously. Note that I'm assuming that low-level input buffers used by IIS/IIS Express/kestrel are rapidly overwritten and that it's the high-level string objects that I'm most concerned with.

Solutions I can think of:

  1. Encrypting the heap/strings on the heap
  2. Updating the model binder to support SecureString (or equivalent)
discussion

All 11 comments

I'll let @blowdart comment on the security aspects, but a couple of thoughts. We've experimented in the .NET Framework with encrypted strings, specifically SecureString. We don't recommend to use this API moving forward. The biggest problem is that as soon as you convert a SecureString to a string you're committing the sin you intended to avoid in the first place. Unfortunately, not many APIs take or produce SecureString and fixing this is akin to introducing a new string type which is (1) really hard and (2) results in the C++ style experience where no two libraries can agree on the type they use for strings.

That being said, I don't think all hope is lost. We're looking into providing a more optimized set of low level APIs that deal in buffers/pipelines rather than deserialized object graphs. We're also looking into having a representation of UTF8 text, ideally baked by a buffer (which could be managed or native memory). Some of these areas will give you more control where data is stored and how long it's available for potential attackers.

However, I also think there isn't really a great answer to the original problem: if the attacker has access to your memory, most hope is already lost. You can try to be defensive about it, but when we start to compromise usability too much, it will not get traction either.

By the time an HTTP request reaches the web server for parsing and turning into something that the framework can act upon it's already been through memory in plain text, possible swapped to disk due to memory pressure, or even dumped into a memory dump should the process crash.

Suddenly taking that, and putting it into SecureString adds no real benefit, compared to the whoppingly huge performance hits such an action would provide.

@terrajobst: I think the most likely scenario I'm interested in protecting against is persistence of the heap to external storage.

I get that, it's the same reason we introduced SecureString. But as @blowdart explained, the string doesn't pop into existence out of thin air; there are often multiple buffers used by the native networking layer which are affected as well. Zeroing out memory isn't always feasible to, especially when you consider buffer pooling and other techniques you need to use to make servers fast.

If you're worried about buffers used for request processing being paged to disk then this is an interesting solution: https://github.com/dotnet/corefxlab/pull/1134.

I was hoping that, at least in managed space, we knew enough about the intermediate objects that it was possible to opt in to security over performance.

I don't have permissions to close this, but I strongly think we should. We've tried this in the past and failed. I don't see enough evidence that we actually need this nor that it's technically feasible.

@JustDre

I was hoping that, at least in managed space, we knew enough about the intermediate objects that it was possible to opt in to security over performance.

No, because you cannot realistically encrypt all strings, you only want to encrypt some strings. In order to do this, everyone would need to pay the penalty of having to deal with different types. Sure, the types could basically not encrypt, but the complexity of multiple types still exists. Given the experience with SecureString I think it's fair to say that this is known not to work...

What about opting in to encrypted heap/strings in the heap?

@JustDre it might make sense to move that discussion to dotnet/coreclr (though it'll probably be closed over there too).

Thing is, even opt-ing in, in the hope that the data doesn't exist anywhere else (a forlorn hope at beast, considering that the socket is going to get this first, and you have no control there), would mean every API that processes everything would also have to take security strings, and then, they'd have to work on them in such a way that they'd never take them out of a security string. Which, when it comes to parsing what are basically strings, is an exercise in futility, even before taking the performance impact into account.

Ditto for "just encrypting" on the heap.

Closing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KLuuKer picture KLuuKer  路  3Comments

Mr-Smileys picture Mr-Smileys  路  3Comments

Lutando picture Lutando  路  4Comments

workmonitored picture workmonitored  路  3Comments

LiangZugeng picture LiangZugeng  路  3Comments