保持敏感数据关闭堆

时间:2017-09-19 20:25:26

标签: c# asp.net-mvc security model-binding checkmarx

在使用Checkmarx扫描ASP.net MVC应用程序时,我经常看到堆检测漏洞。所以我开始怀疑我是否可以使用自定义模型绑定器或内置ByteArrayModelBinder来保持密码和其他敏感字符串不被堆放,以便进行受控处理。我想出了以下解决方案,它通过字节数组发布并显示敏感数据,但我想知道这些数据是否仍然通过某个字符串进入堆中。 (注意:显示操作仅用于调试。)

视图模型

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

输入视图

@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>
}

MCVE

控制器

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);
    }
}

显示视图

@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>

显示输出

enter image description here

*更新*

这表明在ByteArrayModelBinder或任何其他模型绑定器执行之前,表单参数存储在字符串数组中,因此容易进行堆检查。

enter image description here

*更新2 *

如果您查看Microsoft的NetworkCredential实现,您会注意到即使Password属性是一个字符串,SecureString也会在下面用于存储。

2 个答案:

答案 0 :(得分:1)

答案是否定的,你不会让这一点更安全。

为避免在可以恢复的内存中存储机密,您需要使用C#中的SecureString类(或Windows中的底层加密API)。这将通过一些努力来通过在处理时擦除它们来使秘密更难恢复,但也确保它们永远不会在页面文件中结束。

但更重要的是,将秘密打印到网页(即使使用TLS)显然会将秘密暴露给Web堆栈的所有层,使其容易受到多次本地攻击,以及对客户端的浏览器攻击。

解决方案是永远不要以明文形式存储密码,而是使用盐渍哈希。不要试图自己发明这样的东西,使用经过验证的解决方案来安全地验证和存储密码。很容易忽略一些完全阻碍应用程序安全性的东西。例如,加密API具有此功能。例如,请参见:How to store and retrieve credentials on windows using C#

如果您绝对需要接受来自表单的“秘密”用户数据,并且希望防止对服务器的攻击:

  1. 保护进程免受同一台计算机上其他进程的远程攻击(在隔离的VM中运行,在Docker中运行,将所有内容作为单独的(非root用户)运行
  2. 为防止本地攻击,请确保敏感数据不会以永久存储(即SecureString)结束。如前所述,使用当前的实现很难做到这一点,因为您需要强化应用程序的所有层,从SSL / TLS终止到控制器。

答案 1 :(得分:0)

这是一个如何不能始终认真对待静态分析工具的例子。

当密码和敏感数据进入您的应用程序时,猜猜它到达的结构类型是什么? RequestObject,以字符串形式出现。你猜怎么着?它已经在堆上了,你无能为力。当然,你可以玩游戏试图阻止它在你把它传递到你的结构时再次被放到堆上,但这不会改变它已经在其他地方不受控制的事实。

不要误以为SecureString和其他噱头是解决方案。微软现在acknowledges that SecureString isn't what it claims to be,它正从.Net Core中删除。

结论:当他们抱怨堆检测漏洞时,忽略Checkmarx和Fortify等工具。这些规则应该被抛弃。