C# 使敏感数据远离堆

C# 使敏感数据远离堆,c#,asp.net-mvc,security,model-binding,checkmarx,C#,Asp.net Mvc,Security,Model Binding,Checkmarx,在使用Checkmarx扫描ASP.net MVC应用程序时,我经常看到堆检查漏洞。因此,我开始怀疑是否可以使用自定义模型绑定器或内置的ByteArrayModelBinder将密码和其他敏感字符串保留在堆之外,以便进行受控处理。我提出了以下解决方案,通过字节数组发布和显示敏感数据,但我想知道这些数据是否仍然通过某个字符串进入堆中。(注意:显示操作仅用于调试。) 视图模型 public class ByteArrayViewModel { public byte[] SensitiveD

在使用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>
}
@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>
显示视图

@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>
}
@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>
@model MvcHandlingSensativeStrings.Models.ByteArrayViewModel
@{
ViewBag.Title=“字节[]显示”;
Layout=“~/Views/Shared/_Layout.cshtml”;
字符串s=Convert.tobase64字符串(Model.SensitiveData);
}
@视图包。标题
@

@Model.SensitiveData.GetType().ToString()模型

显示输出

*更新*

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

*更新2*


如果您浏览一下Microsoft的NetworkCredential实现,您会注意到,尽管Password属性是字符串,但SecureString在下面用于存储

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

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

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

解决方案是永远不要以明文形式存储密码,而是使用盐哈希。不要试图自己发明这样的东西,使用经验证的解决方案来安全地验证和存储密码。很容易忽略一些完全使应用程序的安全性无效的内容。例如,crypto API有一个用于此的工具。请参见此处的示例:

如果您确实需要接受来自表单的“机密”用户数据,并且希望防止服务器受到攻击,请执行以下操作:

  • 保护进程不受同一台计算机上其他进程的远程攻击(在独立VM中运行、在Docker中运行、以独立(非root)用户身份运行所有程序
  • 为了防止本地攻击,请确保敏感数据不会最终存储在永久性存储(即SecureString)中。正如前面所指出的,使用当前实现很难做到这一点,因为您需要强化应用程序的所有层,从SSL/TLS终止到控制器

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

    当密码和敏感数据进入你的应用程序时,猜猜它进入的是什么类型的结构?一个请求对象,以字符串的形式出现。猜猜看什么?它已经在堆上了,你对此无能为力。当然,你可以玩游戏,试图在你将它传递到应用程序时防止它再次被放在堆上但这不会改变在其他地方已经失控的事实

    不要被愚弄到认为SecureString和其他噱头是解决方案。微软现在,它正在从.NETCore中删除


    一句话:当Checkmarx和Fortify等工具抱怨堆检查漏洞时,请忽略它们。这些规则应该扔掉。

    听起来像是你在试图重新创建类。@mason,SecureString没有内置的模型绑定器,但字节数组有。你真正想做的是什么?通过绑定到s埃克雷特,这个问题与技术无关。你的更新与我的回答一致!RequestObjects将它们的元素存储在一个字符串数组中。你会把创可贴放在一个筛子上吗?我并不是故意刁难,但我只是想指出“我如何在堆外保守秘密”这个问题如果您通过ASP.net堆栈、Razor等传递机密,则与此无关。这与SecureString无关。SecureString没有模型绑定器,因为这将使(已受限制的)无效SecureString.ASP.net MVC的安全性不提供支持SecureString的模型绑定器。我的问题更多的是关于在请求管道中处理此数据的位置。正如我所写的,绑定SecureString会使其无效,因为所有其他层都已经有了该字符串。关于“RequestObject,它以字符串形式出现”。这就是我所怀疑的。我认为你误解了微软在SecureString上的立场。微软承认SecureString用词不当,并不真正“安全”,但不那么不安全。安全是关于保护层和更小的机会窗口。扔掉任何不能100%保证安全和不可穿透的安全措施是愚蠢的。@MarkGood,没错,“不那么不安全的字符串。”Securestring给开发人员带来了很多痛苦,但收效甚微。如果有人能够读取您的内存,那么该字符串是否存在一次或一百次都无关紧要:攻击者只需要它一次!虽然有人可能会争论存在实际好处的场景,但安全机制需要与成本和成本进行权衡预期的好处。根据这样一个指标,SecureString很容易成为我列出的前10个糟糕的安全建议。在内存中保留机密有时是必要的(在生成PK后考虑)