在处理SymmetricAlgorithm时,"try-finally"阻止与"使用"块

Vis*_*ish 5 .net c# encryption

根据System.Security.Cryptography.SymmetricAlgorithmmsdn文档

请注意,在使用派生类时,从安全角度来看,仅在使用完对象后强制执行垃圾回收是不够的.必须在对象上显式调用Clear方法,才能在对象释放之前将其中的任何敏感数据清零.请注意,垃圾收集不会将收集的对象的内容清零,而只是将内存标记为可用于重新分配.因此,垃圾收集对象中包含的数据可能仍然存在于未分配的存储器中的存储器堆中.对于加密对象,此数据可能包含敏感信息,如密钥数据或纯文本块.

.NET Framework中包含敏感数据的所有加密类都实现了Clear方法.调用时,Clear方法用零覆盖对象中的所有敏感数据,然后释放该对象,以便可以安全地进行垃圾回收.当对象已归零并释放时,您应该调用Dispose方法并将disposing参数设置为True以处置与该对象关联的所有托管和非托管资源.

我从中获得的是我必须使用try-finally块来处理我的算法,如下所示:

SymmetricAlgorithm symmetricAlgorithm = SymmetricAlgorithm.Create()
try 
{
     //stuff
}
finally
{
    symmetricAlgorithm.Clear();
    symmetricAlgorithm.Dispose(true)
}
Run Code Online (Sandbox Code Playgroud)

我无法使用更简洁的using

using (var symmetricAlgorithm = SymmetricAlgorithm.Create())
{
    //do stuff
}
Run Code Online (Sandbox Code Playgroud)

因为它不会清除记忆.它只会标记为收藏.那是对的吗?谢谢您的帮助.

Eri*_*ert 17

[调用Dispose]只会将其标记为收藏.那是对的吗?

不,这不正确.你对"Dispose"的作用有误解.这是一个非常普遍的误解.

让我在这一点上非常清楚:"Dispose"本身与垃圾收集完全无关."Dispose"没有什么特别的,你在任何其他方法中都无法做任何其他名称.很多人都相信以下神话:

  • 在实现名为IDisposable的接口的对象上调用一个名为Dispose的方法"标记"要收集的对象.
  • 收集对象时,垃圾收集器调用IDisposable.Dispose.

这些神话都不是真的.

事实是:

  • 完成对象后调用"Dispose"是一种约定,旨在确保在垃圾回收器清理与对象关联的托管内存资源之前清除非托管资源.

  • 垃圾收集器仅基于是否可通过已知的待活对象访问对象的任何引用来决定何时收集对象.调用"Dispose"或任何其他方法不会使对象无法访问.

  • 垃圾收集器(有时)在收集之前不久就会在对象上调用"终结器"(也称为"析构器").作为惯例,对象的作者通常选择使对象的最终化与其处置相同.但同样,这只是一个惯例.

  • 作为惯例,刚刚处置的对象应该告诉垃圾收集器GC最终可以在无法访问时安全地跳过该对象的最终化.

"Dispose"只是一种方法.如果该方法碰巧告诉GC一堆东西,比如"顺便说一下,有人已经负责完成这个对象",那么该方法可以自由地进行."Dispose"中没有固有的魔力.您可以编写自己的方法"MyDispose"和您自己的界面"IMyDisposable",它们做同样的事情; GC既不知道也不关心您选择哪些约定来组织代码,以便尽早释放非托管资源.

  • "在Dispose中没有固有的魔力" - 关于完成和垃圾收集,是的.但值得指出的是,"IDisposable"是"特殊的",因为它是支持一个类型作为`using(...){}`语句的目标所需的接口...这可能有助于它为什么它有些人认为它对垃圾收集有一些特殊的处理方法. (2认同)
  • @SolutionYogi:虽然我完全同意你的观点 - 编写代码以便(1)清楚,(2)完全符合文档中的建议 - 提供加密类型的人是*非常*安全有意识的,不会做出改变,导致常用的模式突然开始默默地打破.期望Dispose和Clear永远是同义词是合理的. (2认同)

And*_*zub 11

以下是Clear方法的实现方法(来自Reflector):

public void Clear()
{
    ((IDisposable) this).Dispose();
}
Run Code Online (Sandbox Code Playgroud)

所以你可以使用using块.