斯坦·德拉普金(Stan Drapkin)。 .NET中的高级密码陷阱

Stan Drapkin是一位安全和合规性专家,在.NET Framework方面拥有超过16年的经验(从2001年开始使用.NET 1.0-beta开始)。 不幸的是,他本人并没有用俄语写文章,因此我们同意他与DotNext Piter一起发布其报告的译文 。 该报告在会议上获得第一名

对称密码学,非对称,混合,高级,低级,流和现代椭圆密码学。 关于加密的视频长达56分钟,而且速度更快-以文本形式。



在剪辑下-视频,幻灯片和翻译。 享受阅读!


滑梯

我叫Stan Drapkin,我是一家专门从事信息安全和法规遵从性公司的技术总监。 另外,我还是几个开源库的作者,这些开源库深受社区欢迎。 有多少人听说过地狱 ? 该库演示了.NET中正确的加密方法, TinyORM为.NET实现了微型ORM。 另外,我写了几本书,可能与今天的文章主题有关。 其中一个是2014版,是“安全驱动的.NET”,另一个是2017年,是“简洁地.NET中的应用程序安全性”。

首先,我们将讨论我所说的加密启发的四个阶段。 然后将出现两个主要主题,第一个主题是对称加密,第二个主题是非对称和混合。 在第一部分中,我们比较了高级和低级加密,并看了一个流式加密的示例。 在第二部分中,我们将对RSA进行很多“尝试”,之后我们将熟悉现代椭圆密码学。

那么,这些阶段的加密启蒙是什么样的呢? 第一阶段-“ XOR太酷了,妈妈,我该怎么办!” 当然,你们中的许多人都熟悉此阶段,并且知道XOR函数的奇迹。 但是,我希望这个阶段的大部分已经发展并转移到下一个阶段,也就是学会使用AES(高级加密标准)来执行加密和解密,AES是一种广为人知且广受好评的算法。 大多数不访问DotNext的开发人员都处于此阶段。 但是,由于您遵循DotNext并熟悉有关低级API的危险的报告,因此您很可能在下一阶段-“我(一件事)做错了一切,我需要切换到高级API”。 好了,为了完整说明这一点,我还将提到最后一个阶段-理解为采用最佳解决方案,可能根本不需要加密。 这个阶段最难实现,很少有人参与。 彼得·诺依曼(Peter G. Neumann)就是一个例子,他说:“如果您认为问题的解决方案在于密码学,那么您根本就不了解问题所在。”

在有关.NET的许多报告中都讨论了低级加密是危险的事实。 您可以参考Vladimir Kochetkov在2015年的报告“ System.Security.Cryptography的陷阱” 。 他的主要思想是,在不了解低级加密API的每个阶段,我们都会做出许多决定,而其中许多我们只是没有适当的知识。 主要结论是,理想情况下,应使用高级密码术代替低级密码术。 这是一个奇妙的结论,但这却引出了另一个问题-我们是否确切知道高级加密的外观? 让我们谈一点。

定义高级加密API的属性。 首先,这样的API不会给人以.NET本机的印象;相反,它将看起来像是一个低级的shell。 此外,这样的API将容易被错误地使用,即。 不是应该的。 另外,它将迫使您生成许多奇怪的底层事物-随机数,初始化向量等。 这样的API会迫使您做出可能不适合您的令人不快的决定-选择算法,填充模式,密钥大小,随机数等。 它还没有正确的流API(流API)-我们将讨论后者的外观。

相反,高级加密API应该是什么样子? 我认为对于代码阅读者和编写者而言,它首先应该是直观且简洁的。 此外,这样的API应该易于学习和使用,并且以错误的方式应用非常困难。 它也必须功能强大,也就是说,它必须允许我们以少量的精力和少量的代码来实现我们的目标。 最后,一般而言,此类API不应包含一连串的限制,注意事项,特殊情况-使用该API时应记住的东西最少,换句话说-应该以低干扰(低摩擦)为特征。毫无保留地工作。

处理了.NET的高级加密API的要求之后,我们现在如何找到它? 您可以尝试使用google,但这太原始了-我们是专业的开发人员,这不是我们的方法。 因此,我们正在研究此问题并测试各种替代方案。 但是为此,我们首先需要为自己创建关于“认证加密”的正确概念,为此,我们需要了解基本概念。 它们如下:纯文本P(纯文本),我们使用一些秘密密钥K(密钥)将其转换为相同长度的密文C(密文)。 如您所见,到目前为止,我们正在使用一个非常简单的方案。 另外,我们还有一个认证标签T和随机数N。一个重要的参数是N̅,即用一个密钥重用随机数。 你们中许多人可能知道,这会导致违反文本的机密性,这显然是不希望的。 另一个重要的概念是AD(关联数据),即关联数据。 这是经过身份验证但不参与加密和解密的可选数据。



了解了基本概念之后,让我们看一下.NET加密库的各种选项。 让我们开始分析Libsodium.NET。 你们当中有多少人认识她? 如我所见,有些人很熟悉。

nonce = SecretAeadAes.GenerateNonce(); c = SecretAeadAes.Encrypt(p, nonce, key, ad); d = SecretAeadAes.Decrypt(c, nonce, key, ad); 

这是Libsodium.NET进行加密 C#代码。 乍看之下,它非常简单明了:在第一行中生成随机数,然后将其用于加密本身的第二行中,以及在第三行中对文本进行解密的现时。 看来-会有什么困难? 首先,Libsodium.NET不提供一种,而是提供三种不同的对称加密方法:

时报

 nonce = SecretAeadAes.GenerateNonce(); c = SecretAeadAes.Encrypt(p, nonce, key, ad); d = SecretAeadAes.Decrypt(c, nonce, key, ad); 

两个

 nonce = SecretAead.GenerateNonce(); c = SecretAead.Encrypt(p, nonce, key, ad); d = SecretAead.Decrypt(c, nonce, key. ad); 



 nonce = SecretBox.GenerateNonce(); c = SecretBox.Create(p, nonce, key); d = SecretBox.Open(c, nonce, key); 

显然,出现了问题-在您的特定情况下哪个更好? 要回答这个问题,您需要深入了解这些方法,我们现在将做这些。

第一种方法SecretAeadAes使用具有96位随机数的AES-GCM。 重要的是他必须有相当长的限制清单。 例如,在使用它时,您一次加密的密钥不应超过550 GB,一条消息中的密钥最多不应超过64 GB,最多2 2 32条消息。 此外,该库不会警告您会接近这些限制,您需要自己对其进行跟踪,这给开发人员带来了额外的负担。

第二种方法SecretAead使用SecretAead一种密码套件ChaCha20/Poly1305 ,它具有明显更小的64位随机数。 这么小的随机数使冲突极有可能发生,仅出于这个原因,您不应该使用此方法-除非在极少数情况下,并且您精通该主题,否则就不要使用此方法。

最后,第三个方法SecretBox 。 应当立即注意,此API的参数中没有关联的数据。 如果需要使用AD进行身份验证的加密,则此方法不适合您。 此处使用的加密算法称为xSalsa20/Poly1305 ,随机数足够大-192位。 然而,缺乏AD是一个重要的限制。

使用Libsodium.NET时 ,会出现一些问题。 例如,在上面的示例中,我们应该对第一行代码生成的随机数进行确切的处理? 图书馆没有告诉我们任何信息,我们必须自己弄清楚。 最有可能的是,我们将手动将该随机数添加到密文的开头或结尾。 此外,我们可能会觉得前两种方法中的AD可以是任意长度。 但是实际上,该库支持AD的长度不超过16个字节-毕竟16个字节对每个人都足够,对吗? 让我们继续前进。 解密错误会怎样? 在此库中,在这些情况下决定引发异常。 如果在您的环境中解密期间可能违反数据完整性,那么您将有许多异常需要处理。 如果密钥大小不完全是32个字节怎么办? 图书馆没有告诉我们任何有关此的信息,这些是您不感兴趣的问题。 另一个重要主题是字节数​​组的重用,以减轻密集型场景中垃圾回收器的负担。 例如,在代码中,我们看到了随机数生成器返回给我们的数组。 我不想每次都创建一个新的缓冲区,而是要重用现有的缓冲区。 在此库中这是不可能的,每次都会重新生成一个字节数组。

使用我们已经看到的方案,我们将尝试比较各种Libsodium.NET算法。



第一种算法AES-GCM使用96位随机数(图片中的黄色列)。 它小于128位,这会带来一些不适,但不太明显。 下一列是蓝色,这是身份验证标签所占用的位置,对于AES-GCM,它是16字节或128位。 括号中的第二个蓝色数字表示此标签中包含的熵或随机量-少于128位。 少多少-该算法取决于加密的数据量。 加密程度越高,标记越弱。 仅此一项就引起人们对该算法的怀疑,只有在我们看白列时才会增加。 它说随机数的重复(冲突)将导致伪造同一密钥创建的所有密文。 例如,如果在一个公共密钥创建的密文中有100个(分为两个),则存在一次随机数冲突,该随机数将导致身份验证密钥的内部泄漏,并使攻击者能够伪造此密钥创建的任何其他密文。 这是一个非常重要的限制。

让我们继续第二个Libsodium.NET方法。 就像我说的那样,这里的随机数占用的空间太少,只有64位。 该标签占用128位,但仅包含106位或更少的熵,换句话说,它大大低于大多数情况下尝试实现的128位的安全级别。 至于伪造,这里的情况要比AES-GCM好一些。 随机数冲突会导致密文的伪造,但仅适用于发生冲突的那些块。 在前面的示例中,我们将伪造2个密文,而不是100个。

最后,在xSalsa / Poly算法的情况下,我们有一个非常大的192位随机数,这使得冲突极不可能发生。 身份验证方法与前面的方法相同,因此标签再次占用128位,并且具有106位或更少的熵。

将所有这些数字与Inferno库的相应指标进行比较。 在其中,nonce占据了巨大的空间,即320位,这使得碰撞几乎是不可能的。 至于标签,一切都很简单:它恰好占据了128位,熵也恰好具有128位,不少于。 这是可靠且安全的方法的一个示例。

在更详细地了解Libsodium.NET之前,我们需要了解它的用途-不幸的是,并不是每个使用此库的人都知道它。 为此,请参阅其文档,该文档指出Libsodium.NETlibsodium的C#包装器。 这是另一个开源项目,其文档说它是具有兼容API的NaCl的分支。 好了,转到另一个开放源代码项目NaCl的文档。 其中目标假定NaCl提供创建高级加密工具所需的所有必要操作。 这只狗被埋在这里: NaCl及其所有外壳的任务是提供低级元素,然后其他人已经可以从中组装出高级密码API。 这些shell本身并不是高级库。 这就是道德:如果您需要高级密码API,则需要查找高级库,而不是使用低级包装器,并假装您正在使用高级库。

让我们看看加密在Inferno中如何工作。



这是示例代码,其中与Libsodium一样 ,每次加密和解密仅占用一行。 参数是键,文本和可选的关联数据。 应当指出的是,没有随机数,没有必要做出任何决定,如果发生解密错误,它只会返回null,而不会引发异常。 由于创建异常会大大增加垃圾收集器的负载,因此对于处理大型数据流的脚本,异常的缺失非常重要。 我希望我能说服您这种方法是最佳的。

出于兴趣,让我们尝试加密一些字符串。 这应该是每个人都可以实现的最简单的方案。 假设我们只有两个不同的字符串值:“ LEFT”和“ RIGHT”。



在图片中,您可以看到使用Inferno对这些行进行加密(尽管在此示例中,使用哪个库都没有关系)。 我们用一个密钥加密两行,并得到两个密文c1c2 。 这段代码中的所有内容都正确吗? 他准备好要生产了吗? 有人可能会说这是短期内可能出现的问题,但距离主要问题还很遥远,因此我们将假定密钥使用相同,并且长度足够。 我的意思是:采用传统的加密方法,我们示例中的c1会比c2短。 这称为长度泄漏-在许多情况下, c2c1长一个字节。 这可能使攻击者了解该密文“ LEFT”或“ RIGHT”代表哪个字符串。 解决此问题的最简单方法是使两行的长度相同-例如,在“ LEFT”行的末尾添加一个字符。

乍一看,长度泄漏被认为是一个牵强附会的问题,在实际应用中不会遇到。 但在2018年1月,《有线》杂志上发表了一篇文章,其中涉及以色列公司Checkmarx进行的一项研究,标题为“ Tinder中缺乏加密,因此外来者可以在您滑动屏幕时进行跟踪。” 我将简要介绍一下内容,但首先是对Tinder功能的粗略描述。 Tinder是一种接收照片流的应用程序,然后用户根据自己是否喜欢照片来向右或向左滑动屏幕。 研究人员发现,尽管使用TLS和HTTPS对命令本身进行了正确的加密,但是右命令的数据字节数与左命令的字节数不同。 当然,这是一个漏洞,但它本身并不太重要。 对于Tinder而言,更重要的是,他们通过常规HTTP在没有任何加密的情况下使用照片发送了带有照片的流。 因此,攻击者不仅可以访问用户对照片的反应,还可以访问照片本身。 因此,如您所见,长度泄漏是一个非常实际的问题。

现在让我们尝试加密文件。 立即我必须说,在Libsodium.NET文件加密或更广泛地说,流加密不是默认情况下实现的,它必须在那儿手动完成-相信我,这很难正确完成。 在Inferno中 ,这样做会更好。



上面,您看到的示例与MSDN几乎没有任何变化。 这很简单,在这里我们看到一个用于源文件的流,另一个用于目标文件的流,以及将第一个转换为第二个的加密流。 在此代码中, Inferno仅在转换发生的一行中使用。 因此,摆在我们面前的是一个简单而又经过全面测试的流加密解决方案。

应当记住,当使用相同的密钥加密时,我们对消息的数量有限制。 它们存在于Inferno中 ,并且在此库中将它们清楚地写在屏幕上。 但是,与此同时,它们在Inferno中是如此之大,以至于在实践中您将永远无法到达它们。 在Libsodium.NET中,对于不同的算法,限制是不同的,但是在所有情况下,它们都足够低,可以被超过。 因此,您需要检查它们是否会在每种情况下实现。

我们还应该讨论关联数据的身份验证,因为这是一个很少涉及的主题。 AD可能是“弱”的:这意味着它们已通过身份验证,但它们不参与加密和解密过程。 相反,“强” AD会自行更改此过程。 我知道的大多数AD库都很弱,而Inferno使用第二种方法,即在加密/解密过程本身中使用AD。

它还应该详细说明应为高级加密而努力的安全级别。 简而言之,我的答案是:具有128位身份验证标签的256位加密。 为什么钥匙这么大? 造成这种情况的原因很多,但每种原因本身都很重要,但是现在我希望您记住一件事:在生成加密密钥时,我们需要保护自己免受可能的偏见。 让我解释一下偏见的含义。 对于没有偏差的随机位生成器,对于每个位,接受值0或1的概率是相等的。 但是,假设在我们的生成器中,该位将取值为1,概率为56%,而不是50%。 乍一看,这种偏见很小,但实际上却很明显:25%。 现在,让我们尝试计算使用生成器生成一定数量的位时得到的熵。



在图片中,您可以看到进行计算的公式。 重要的是其中只有两个变量:我们已经讨论过的偏差(bias)以及生成器创建的位数。 我们假设偏差为25%-这是一个极端的情况,在实践中,您很可能无法在具有如此失真的随机数生成器的系统中工作。 无论如何,在25%的偏差和128位密钥的情况下,我们只能得到53位的熵。 首先,它大大少于通常由随机数生成器期望的128位,其次,对于现代技术而言,这种密钥简直就是蛮力。 但是,如果不是使用128位密钥而是使用256位密钥,则将获得106位熵。 尽管比预期的256个要少,但它已经相当不错了。使用现代技术,几乎不可能破解这样的密钥。

在报告第一部分的结尾,我将总结中期结果。 我建议每个人都使用编写良好的加密API。 找到一个适合您的人,或向Microsoft发送请愿书给您。 此外,在选择API时,您应注意对使用线程的支持的可用性。 由于已经说明的原因,最小密钥长度应为256位。 最后,应该牢记,高级加密技术与其他加密技术一样都不理想。 可能会发生泄漏,在大多数情况下,必须牢记其功能。

让我们谈谈非对称或混合密码学。 我将提出一个棘手的问题:您可以在.NET中使用RSA吗? 不要像许多人一样急于回答肯定的问题-让我们首先测试您在这一领域的知识。 以下幻灯片将专门为已经熟悉此主题的人们设计。 但是首先,让我们看一下Wikipedia,并牢记什么是RSA,以防万一有人忘记或长时间不使用此算法。



假设有一个爱丽丝使用一个随机数生成器创建了一个包括一对私人和一个公共的密钥对。 接下来,有一些鲍勃想要加密给爱丽丝的消息:“你好爱丽丝!” 他使用她的公共密钥生成一个密文,然后将其发送给她。 她使用密钥的私有部分解密该密文。

让我们尝试在实践中重现这种情况。



如上所示,我们创建了一个RSA实例并加密了一些文本。 立即注意.NET迫使我们选择填充模式。 其中有五个,名字都不清楚。 如果依次尝试所有方法,我们将发现后三个方法只会引发异常,并且不起作用。 我们将使用其余两个OaepSHA1 。 在这里,密钥的大小为1 KB,对于RSA来说太小了,实际上是一个破解的密钥。 因此,我们必须手动设置密钥大小。 从文档中我们了解到,有一个特殊属性.KeySize ,它接收或设置密钥大小。



乍一看,这正是我们所需要的,因此我们编写: rsa.KeySize = 3072 。 但是,如果在含糊的怀疑的指导下,然后检查密钥大小现在等于什么,那么我们将发现它仍然需要1 kb。 没关系,我们将使用WriteLine(rsa.KeySize)方法或rsa.ExportParameters(false).Modulus.Length * 8来检查此参数。 该密钥的模数是一个数组,我们将其乘以8并得到以位为单位的大小-再次为1千位。 如您所见,此算法尚不成熟,无法投入生产。

我们不会浪费时间弄清楚该API为何不起作用;而是尝试由Microsoft在.NET 4.6中提供的另一种RSA实现,即一个全新的实现。 它称为RSACng ,而Cng代表下一代加密技术。 太好了,谁不想使用下一代工具? 当然,在这里我们将为所有问题找到神奇的解决方案。



我们请求一个RSACng实例,再次将密钥大小设置为3 KB,再次通过WriteLine(rsa.KeySize)检查密钥大小-并再次发现密钥大小仍等于1 KB。 另外,如果我们请求生成密钥的对象的类型-正如我们回想的那样,我们请求了RSACng的实例-我们发现它是RSACryptoServiceProvider。 我只想在这里分享我的绝望感,然后大喊:“为什么,微软?!”

经过长时间的折磨和折磨,我们发现实际上您需要使用设计师,而不是工厂。



这里的默认密钥大小值为2048位,这已经更好了。 更好的是-在这里我们终于设法将密钥大小设置为3 KB。 正如他们所说,成就已解锁。

让我提醒您,到目前为止,我们的所有努力都只限于创建RSA,我们甚至还没有开始加密。我们仍然需要首先回答一些问题。首先,您可以在多大程度上依赖默认密钥大小?可能会在中覆盖RSA工厂的实现machine.config,因此,它可能会在您不知情的情况下发生更改(例如,系统管理员可能会对其进行更改)。这意味着默认密钥大小也可以更改。因此,您永远不应信任默认提供的值,密钥大小应始终独立设置。接下来,默认RSA密钥大小有多好? .NET中有两种RSA实现,一种基于RSACryptoServiceProvider,另一种基于RSACng。在第一个中,默认大小为1 KB,在后两个中。为了好玩,让我们将这些值与比特币(BCN)网络上的值进行比较。我事先提出了一个痛苦的话题表示歉意,但是我们不会讨论比特币或加密货币,我们只会谈论网络本身。她有一个已发布的哈希率,并且每个月都在增长,今天等于每秒2 64个哈希。这相当于每年2 90个哈希。为简单起见,假设哈希值等同于基本操作-尽管这并非完全正确,但更为复杂。如果您读的是真正的专业人士(而不是像我这样的人)写的有关密码学的书,那么您会知道2 70次操作(即BCN的一分钟)足以破解1千位RSA密钥,而2 90(BCN一年)-破解2 KB密钥。这两个值都应该引起我们的焦虑-这可以通过现有技术来实现。因此,我强烈建议您始终自行设置密钥大小,并将其大小至少设置为3 KB,如果性能允许,则为4

.。在.NET中,弄清楚如何导出公钥和私钥并不容易。



在幻灯片的顶部,您可以看到RSA密钥的两个实例,第一个来自RSACryptoServiceProvider,第二个来自RSACng每个4千位。下面的代码用于从两个实例中提取公钥和私钥。应该注意的是,这两个API彼此完全不同-不同的代码,不同的方法,不同的参数。此外,如果我们比较第一和第二副本的公共密钥的大小,我们会发现它们是可比较的,每个大约半千字节。但是,新的RSA实施的私钥比旧的要小得多。有必要牢记这一点并遵守统一性,以免干扰这两个API。

到目前为止,我们对RSA所做的一切都归结为试图获得工作副本。现在尝试加密某些内容。



创建一个字节数组,这将是我们的纯文本(data),然后我们将使用不会引发异常的其他加法模式之一对其进行加密。但是这次我们有一个例外。这是无效参数的例外;但是我们在说什么参数?我不知道-微软也很有可能。如果我们尝试在其他补充模式下运行相同的方法,那么在每种情况下,我们都会得到相同的异常。因此,重点不在补充模式。因此问题出在源代码本身。很难说他出了什么问题,所以让我们把它切成两半,以防万一。这次,加密成功。我们感到困惑。

也许整点是我们使用了SHA-1补充剂?我们知道,SHA-1不再具有强大的加密功能,因此我们的审计师和合规部门坚称我们要摆脱它。替换OaepSHA1OaepSHA256,至少它将使审核员放心。



但是,当我们尝试加密时,我们再次得到错误参数的异常。整个情况是由于以下事实引起的:对可以传输到密码功能的文本大小的限制不仅取决于补充模式,还取决于密钥的大小。

让我们尝试找出确切的魔术公式,它确定最大的加密数据量。它必须在方法中int GetMaxDataSizeForEnc(RSAEncryptionPadding pad),它已在输入端接收到补充模式,从而计算了此音量。我发明了这种方法的主要缺点是它不存在。我试图传达的想法是,即使开发人员正确使用RSA所需的最基本信息也无法提供给我们。谢谢,微软。

这就是为什么即使是签名也应避免使用RSA的原因。正如我希望设法证明的那样,.NET中用于RSA的API极其不令人满意。您不得不对补充模式,数据大小等做出许多决定,这是不希望的。此外,对于128位安全级别,您至少需要一个非常庞大的4 KB密钥。它将为您提供一个千字节的私钥,一个半字节的公钥和一个半字节的签名。对于许多情况,这样的值可能是不希望的。而且,如果您尝试实现256位安全级别,则将需要一个巨大的密钥-15360位。在RSA中,几乎不可能使用这样的密钥。在我的笔记本电脑上,这样一个密钥生成了一个半分钟。除此之外,RSA作为一种算法,无论采用何种实现方式,在基本级别上都非常缓慢地实现签名。为什么签名速度对我们很重要?如果您将TLS与RSA证书一起使用,则签名在服务器上完成。作为开发人员,我们受服务器上发生的事情的影响最大,我们对此负责,它的吞吐量对我们很重要。总而言之,我想再次建议不要使用RSA。我想再次建议不要使用RSA。我想再次建议不要使用RSA。

在这种情况下,什么可以取代RSA?我想向您介绍现代椭圆加密基元。首先,请记住ECDSA(数字签名算法),可以使用它代替RSA进行签名。在此缩写以及以下缩写中,EC是一个通用前缀,代表“椭圆曲线”(“ elliptical”)。在securitydriven.net/inferno/#DSA签名中,您可以找到示例ECDSA代码,该代码是.NET固有的。另一个重要的算法是ECIES(集成加密方案,“椭圆集成加密方案”)。该算法可以执行混合加密而不是RSA,也就是说,您可以生成对称密钥,使用对称密钥对数据进行加密,然后再对密钥本身进行加密。示例代码可从securitydriven.net/inferno/#ECIES示例获得。最后,另一个非常重要的算法是ECDH(Diffie-Hellman密钥交换,“ Diffie-Hellman密钥交换”)。它使您可以创建具有已知公钥的两方之间对称加密的密钥。在某些情况和使用方法中,它允许直接保密(前向保密)。链接securitydriven.net/inferno/#DHM主要交易所提供的示例代码。

总结有关非对称加密的讨论。您应该始终使用不会强迫您做出尚未准备好的决定的高级API。我也建议停止使用RSA。当然,这说起来容易做起来难,因为我们所有人都使用大型的,已经创建的应用程序,这些应用程序可能无法完全重构。在这种情况下,至少您需要学习如何正确使用RSA。此外,我建议您熟悉现代的椭圆密码算法(ECDSA,ECDH,ECIES)。最后,重要的是高级加密不能神奇地解决所有问题,因此您需要记住您追求的目标。我将引用StackOverflow的观点,我完全同意:“仅加密技术并不能解决问题。对称加密只会使数据隐私成为关键的管理问题。”

我会说一些对您有用的资源。有一个相对可接受的高级SecurityDriven.Inferno库,其中包含良好的文档。 Jean-Philippe Aumasson撰写的一本很棒的书《严重密码学》是《严重密码学》。结合最新的创新,它概述了加密技术的当前状态。另外,我已经在公共领域简明地写了已经提到的.NET中的Application Security一书。它甚至包含有关.NET安全陷阱的更多信息。最后,Slideshare上的Vladimir Kochetkov进行了精彩的演讲,以一种较为简单但非常扎实的方式概述了应用程序安全性理论的基础,并解释了各种危险源。

最后,让我们看看我准备的一些其他示例。在开始的时候,我谈到了加密启发的第四阶段,其中意识到最好的解决方案可能根本不需要加密。让我们看一个这样的解决方案的例子。让我们看一下经典的.NET机制-CSRF(跨站点请求伪造,“跨站点请求伪造”),旨在防止包括跨站点请求伪造在内的一类攻击。在此模型中,我们有一个用户代理-通常是浏览器。它尝试通过发送GET请求与服务器建立连接。作为响应,服务器发送CSRF令牌,该令牌被隐藏在HTML“隐藏”字段中。另外,相同的令牌作为cookie(作为标头)附加到响应。用户处理某种形式并执行POST,该POST将使用两个令牌返回到服务器。服务器首先检查两个令牌是否都已发送,其次检查它们是否匹配。正是这种身份比较使服务器可以保护自己免受攻击者的攻击。这是内置在ASP.NET和ASP.NET Core中的经典机制。 Mikhail Shcherbakov作了出色的报告,对CSRF的工作进行了详细调查。

这种方法的问题在于CSRF令牌生成使用加密。困难在于加密本身是一项复杂且消耗资源的操作,它会加载处理器,需要内存并增加延迟。所有这些都是不可取的。另外,注入令牌是一个麻烦,混乱且不便的过程。在许多情况下(例如,在使用AJAX异步调用时),开发人员将取决于您的实现。那些这样做的人知道,这种活动是非常不愉快的。



相同或相当的加密可在不使用的加密,如何创建-在滑动显示。我知道这里的文本非常复杂,因此我准备在讨论区域中对其进行详细讨论。这就是我的全部,非常感谢。

. DotNext. DotNext 2018 Moscow — 22-23 2018 - « ».

. , , . ! .

Source: https://habr.com/ru/post/zh-CN428121/


All Articles