1

While scanning an ASP.net MVC application using Checkmarx, I regularly see heap inspection vulnerabilities. So I started to wonder if I could use a custom model binder or the built-in ByteArrayModelBinder to keep passwords and other sensitive strings out of the heap, for controlled disposal. I came up with the following solution which posts and displays the sensitive data via a byte array, but I am wondering if this data is still making its way into the heap through a string somewhere. (Note: The display action is just for debugging.)

ViewModel

public class ByteArrayViewModel
{
    public byte[] SensitiveData { get; set; }        
}

Input View

@model MvcHandlingSensativeStrings.Models.ByteArrayViewModel

@{
    ViewBag.Title = "byte[] Post";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>@ViewBag.Title</h2>
@using (Html.BeginForm("Post", "ByteArray", FormMethod.Post))
{
    @Html.TextBoxFor(m=>m.SensitiveData);
    <button type="submit">Send</button>
}

enter image description here

Controller

public class ByteArrayController : Controller
{
    public ActionResult Index()
    {
        return View(new ByteArrayViewModel());
    }

    [HttpPost]
    public ActionResult Post(ByteArrayViewModel viewModel)
    {
        try
        {
            // Handle sensitive data here
            return View("Display", viewModel);
        }
        catch
        {
            return View("Index");
        }
        finally
        {
            // Clear sensitive data from memory
            //Array.Clear(viewModel.SensitiveData, 0, viewModel.SensitiveData.Leng
        }
    }

    public ActionResult Display(ByteArrayViewModel viewModel)
    {
        return View(viewModel);
    }
}

Display View

@model MvcHandlingSensativeStrings.Models.ByteArrayViewModel

@{
    ViewBag.Title = "byte[] Display";
    Layout = "~/Views/Shared/_Layout.cshtml";
    string s = Convert.ToBase64String(Model.SensitiveData);
}

<h2>@ViewBag.Title</h2>
<p>@s</p>
<p>@Model.SensitiveData.GetType().ToString()</p>

Display Output

enter image description here

* Update *

This shows that before ByteArrayModelBinder or any other model binder executes, form parameters are stored in an array of strings and are thus susceptible to heap inspection.

enter image description here

* Update 2 *

If you peek at Microsoft's implementation of NetworkCredential, you will noticed that even though the Password property is a string, SecureString is used underneath for storage.

Mark Good
  • 4,271
  • 2
  • 31
  • 43
  • 3
    Sounds like you're trying to reinvent the [SecureString](https://msdn.microsoft.com/en-us/library/system.security.securestring(v=vs.110).aspx) class. – mason Sep 19 '17 at 20:36
  • @mason, there is no built in model binder for SecureString, but there is for byte arrays. – Mark Good Sep 20 '17 at 11:36
  • What are you trying to accomplish really? By binding to a secret, the question is irrelevant, regardless of technique. – Krumelur Sep 20 '17 at 16:33
  • Your Update is consistent with my reply! RequestObjects store their elements in an array of strings. Would you put band-aids on a sieve? – TheGreatContini Sep 20 '17 at 21:44
  • @Krumelur, TheGreatContini, while I appreciate you engaging with me in this Q&A, your snarkiness is unhelpful and detracting. The question & discussion ARE relevant, as demonstrated by the .NET Core Design Review surrounding SecureString (https://www.youtube.com/watch?v=28xZ7Xb5MhE). Clearly, the Core designers grappled with the same questions. So, why no upvote on the question? Are you so arrogant to suggest that you've never asked the same question? Unlikely. Your answers would have been much more helpful had you simply shared your knowledge and experience. – Mark Good Sep 21 '17 at 11:54
  • 1
    I did not mean to be snarky, but I just wanted to point out that the question "how do I keep secrets out of my heap" is irrelevant if you pass the secret through the ASP.net stack, Razor and whatnot. This has nothing to do with SecureString. There is no model binder for SecureString because that would void the (already limited) security of the SecureString. – Krumelur Sep 21 '17 at 12:25

2 Answers2

2

This is an example of how static analysis tools cannot always be taken seriously.

When passwords and sensitive data come into your application, guess what type of structure it is arriving in? A RequestObject, which comes in as a string. Guess what? It's already on the heap, and there is nothing you can do about it. Sure, you can play games trying to prevent it from being put on the heap again when you pass it on to your structures, but that is not going to change the fact that it is already uncontrolled elsewhere.

Don't be fooled into thinking SecureString and other gimmicks are the solution. Microsoft now acknowledges that SecureString isn't what it claims to be, and it is being dropped from .Net Core.

Bottom line: ignore tools like Checkmarx and Fortify when they complain about heap inspection vulnerabilities. These rules should be thrown out.

TheGreatContini
  • 6,429
  • 2
  • 27
  • 37
  • Regarding "RequestObject, which comes in as a string.". This is what I suspected. – Mark Good Sep 20 '17 at 11:57
  • I think you're misrepresenting Microsoft's position on SecureString. MS acknowledges that SecureString is a misnomer, that it's not really "secure", but less insecure. Security is about layers of protection and smaller windows of opportunity. To throw out any security measure that isn't 100% guaranteed to be secure and impenetrable, is foolish. – Mark Good Sep 20 '17 at 12:01
  • 2
    @MarkGood that's correct, "less insecure string." Securestring has caused a lot of pain to developers for little to no gain. If somebody can read your memory, it doesn't matter if the string is in there one time or one hundred times: the attacker only needs it once! While one can argue scenarios where there is a practical benefit, security mechanisms need to be weighed against there cost and expected benefit. By such a metric, SecureString easily makes my list of top 10 bad security recommendations. – TheGreatContini Sep 20 '17 at 12:32
  • 1
    Keeping secrets in memory is sometimes a necessity (consider after generating a PK before encrypting). However, care should be taken to keep this data in few places, limit access to other processes, randomize addresses, keep it out of the page file and “burn” it after its use. In that context, the SecureString is sometimes useable. In the context of the OP, SecureString or not, the code is not secured against any of these attacks. – Krumelur Sep 20 '17 at 16:30
  • If you peek at Microsoft's implementation of NetworkCredential, you will noticed that even though the Password property is a string, SecureString is used underneath for storage. – Mark Good Mar 29 '18 at 12:26
1

The answer is no, you are not making this one bit more secure.

To avoid storing secrets in memory that could be recovered, you need to use the SecureString class in C# (or the underlying crypto API in Windows). This will go through some effort to make the secrets harder to recover by erasing them on dispose, but also making sure they never end up in the pagefile.

But more importantly, printing the secrets out to the web page (even if using TLS) obviously exposes the secret to all layers of the web stack, making it vulnerable to multiple local attacks, as well as browser attacks on the client.

The solution is to never ever store passwords in clear text, and instead use salted hashes. Don't try to invent stuff like this yourself, use proven solutions for verifying and storing passwords securely. It is very easy to overlook something that completely voids the security of your application. For example, the crypto API has a facility for this. See for example here: How to store and retrieve credentials on windows using C#

If you absolutely need to accept "secret" user data coming from a form, and you want to protect against attacks on the server:

  1. Protect the process against remote exploits in other processes on the same machine (run in isolated VM, run in Docker, run everything as separate (non-root) users
  2. To protect against local attacks, make sure that the sensitive data does not end up in persistent storage (i.e. SecureString). This will be hard to do using your current implementation as already pointed out, as you need to harden all layers of your application, from SSL/TLS termination and down to the controller.
Krumelur
  • 31,081
  • 7
  • 77
  • 119
  • ASP.net MVC does not offer a model binder that supports SecureString. My question was more about where in the request pipeline this data is handled. – Mark Good Sep 20 '17 at 11:45
  • As I wrote, binding the SecureString voids its purpose, as all other layers already have the string. – Krumelur Sep 20 '17 at 12:00