1

在使用 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>
}

在此处输入图像描述

控制器

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>

显示输出

在此处输入图像描述

* 更新 *

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

在此处输入图像描述

* 更新 2 *

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

4

2 回答 2

2

这是静态分析工具不能总是被认真对待的一个例子。

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

不要误以为 SecureString 和其他噱头是解决方案。微软现在承认 SecureString 不是它声称的那样,并且它正在从 .Net Core 中删除。

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

于 2017-09-20T03:10:22.233 回答
1

答案是否定的,你并没有让这更安全一点。

为避免在内存中存储可恢复的机密,您需要使用 C# 中的 SecureString 类(或 Windows 中的底层加密 API)。这将通过一些努力使秘密更难恢复,方法是在处置时删除它们,同时确保它们永远不会出现在页面文件中。

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

解决方案是永远不要以明文形式存储密码,而是使用加盐哈希。不要试图自己发明这样的东西,使用经过验证的解决方案来安全地验证和存储密码。很容易忽略完全破坏应用程序安全性的东西。例如,加密 API 有一个功能。请参阅此处的示例:如何使用 C# 在 Windows 上存储和检索凭据

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

  1. 保护进程免受同一机器上其他进程的远程攻击(在隔离的 VM 中运行,在 Docker 中运行,以单独(非 root)用户身份运行所有内容
  2. 为防止本地攻击,请确保敏感数据不会在持久存储(即 SecureString)中结束。正如已经指出的那样,使用您当前的实现将很难做到这一点,因为您需要强化应用程序的所有层,从 SSL/TLS 终止到控制器。
于 2017-09-19T20:45:21.027 回答