在这篇文章中,我将介绍ASP.NET Core 数据保护系统:它是什么,为什么我们需要它,以及它如何工作。
为什么我们需要数据保护系统?
数据保护系统是ASP.NET Core使用的一组加密api。加密必须由不受信任的第三方处理的数据。
这方面的典型例子是身份验证cookie。cookie是在请求之间持久化状态的一种方法。你不希望每次向服务器请求时都必须提供用户名和密码,这将非常麻烦!
相反,只需向服务器提供一次凭据。服务器验证你的详细信息,并发出一个cookie,表明“他不需要提供任何其他证明,相信他。”对于后续的请求,可以简单地提供该cookie,而不必提供凭据。浏览器自动发送cookie与后续请求,这是web为用户实现流畅登录体验的方式。
cookie是非常敏感的东西。任何包含cookie的请求都将被视为原始用户发送的请求,就像原始用户在每个请求中都提供了用户名和密码一样。浏览器中有很多保护措施(例如CORS)来阻止攻击者访问这些cookie。
然而,这不仅仅是阻止别人得到你的cookie。作为一个网站所有者,你也不希望用户篡改他们自己的cookie。
身份验证cookie通常不仅仅包含经过身份验证的用户的ID或名称。它们通常包含各种附加的要求。它包含了用户的详细信息。它们可以是真实数据,如名称、电子邮件或电话号码,但它们也可以是与权限相关的声明,如是否是管理员或是否可以编辑。
对于每个请求,通常都需要这些,以确定是否允许用户采取操作。通常包含在发送给用户的身份验证cookie中,而不是每次请求都必须从数据库加载。
这使得应用程序更加容易——一旦通过从cookie中提取用户主体对用户进行身份验证,应用程序就会确切地知道用户拥有哪些权限。这意味着应用程序必须信任cookie。如果cookie是明文发送的,那么用户只需编辑这些值,就会暴露应用程序中明显的安全漏洞。
ASP.NET Core数据保护系统正是为了这个目的而使用的。它对敏感数据(如身份验证cookie)进行加密和解密。通过在响应中返回身份验证cookie之前对其进行加密,应用程序知道该cookie没有被篡改,并可以信任其值。
数据保护系统如何工作?
数据保护系统试图解决一个棘手的问题:如何保护暴露给攻击者的敏感数据,理想情况下不向开发人员暴露任何密钥,同时遵循加密的最佳实践。
数据保护系统使用对称密钥加密来保护数据。使用包含随机数据的密钥加密数据,使用相同的密钥解密数据。
在一个典型的ASP.NET Core应用程序可能有几种不同类型的不相关数据需要加密。例如,除了身份验证cookie之外,可能还需要加密跨站点请求伪造令牌(CSRF)或密码重置令牌。
你可以将相同的键用于所有这些不同的目的,但这可能会带来问题。例如,如果密码重置令牌不能“意外地”(更有可能是恶意地)用作身份验证令牌,那就好得多。
ASP.NET Core数据保护系统实现了这一目标。数据保护系统有一个不能直接使用的父密钥。必须从父密钥派生子密钥,这些子密钥用于加密和解密数据。
使用相同的purpose字符串从父密钥派生密钥总是会给出相同的密钥,因此如果你拥有父密钥并且知道purpose字符串,那么总是可以解密已加密的数据。如果密钥是用不同的purpose导出的,那么尝试解密数据将会失败。这样可以保持数据隔离,这对安全性更好。
在大多数情况下,你不必直接与数据保护系统交互来创建密钥或加密数据。这是由ASP.NET Core核心框架及其附带的库处理的。它们确保在你的应用程序中为每个不同的purpose使用唯一的字符串。如果你愿意,你可以创建自己的保护程序并加密其他数据(见下文),但这不是ASP.NET Core的日常运行所必需的。
我是一个.net框架开发者——这听起来很像<machineKey>?
数据保护系统是ASP.NET Core的一个新功能。,但是保护身份验证令牌的需要并不是新的,那么我们以前用的是什么呢?答案是<machineKey>。<machineKey>元素的使用方式与ASP.NET Core数据保护系统非常相似,配置密钥和密码学套件,用于通过身份验证系统加密数据(以及其他地方)。不幸的是,使用这个密钥时有些复杂,因为它通常是从machine.config读取的。必须在运行应用程序的机器上配置。在集群中运行时,必须确保这些键保持同步,否则可能会产生问题!
在.net Framework 4.5中,我们可以替换<machineKey>元素及其使用的整个加密管道。
如何管理数据保护密钥?
如果对安全性有所了解,那么你可能已经听到应该定期轮换密码、机密和证书的说法。如果你的某个秘密被泄露了,这可以在一定程度上减少影响。这就是为什么签发HTTPS证书的寿命越来越短的原因。
根据你从框架和工具获得的支持,更换秘钥和证书可能会很痛苦,特别是在过渡时期,可能需要同时支持新旧秘钥。
鉴于数据保护对于保护ASP.NET Core是至关重要的。你不会惊讶秘钥轮换是数据保护系统的默认设置。默认情况下,数据保护的生命周期为90天,但通常不必为此担心。当旧密钥快要过期时,数据保护系统会自动创建新的密钥。所有可用密钥的集合称为密匙环。
在这篇文章中,我不会深入密钥管理的细节。请注意,秘钥轮换是自动发生的,只要你不删除任何旧的键(或显式地撤销它们),那么加密的数据仍然可以使用过期的键检索。过期的密钥不能用于加密新数据。
我是否也可以保护其他数据,还是仅用于身份验证cookie?
数据保护系统由ASP.NET Core隐含地使用并处理认证令牌的加密和解密。它也被ASP.NET Core用来保护密码重置和MFA令牌。你不需要为这种保护做任何事情——框架自己处理保护。
如果你有自己想要加密的临时数据,可以直接使用数据保护api。我将在后面的文章中详细介绍,但以下内容展示了中如何使用IDataProtectionProvider服务(默认在ASP.NET Core apps)加密和解密一些数据:
public class MyClass { // The IDataProtectionProvider is registered by default in ASP.NET Core readonly IDataProtectionProvider _rootProvider; public MyClass(IDataProtectionProvider rootProvider) { _rootProvider = rootProvider; } public void RunSample() { // Create a child key using the purpose string string purpose = "Contoso.MyClass.v1"; IDataProtector protector = provider.CreateProtector(purpose); // Get the data to protect Console.Write("Enter input: "); string input = Console.ReadLine(); // Enter input: Hello world! // protect the payload string protectedPayload = _protector.Protect(input); Console.WriteLine($"Protect returned: {protectedPayload}"); //PRINTS: Protect returned: CfDJ8ICcgQwZZhlAlTZT...OdfH66i1PnGmpCR5e441xQ // unprotect the payload string unprotectedPayload = _protector.Unprotect(protectedPayload); Console.WriteLine($"Unprotect returned: {unprotectedPayload}"); //PRINTS: Unprotect returned: Hello world } }
一般来说,这并不是你想要做的事情。我个人只在处理密码重置和类似的令牌时需要它。
有什么是我不应该使用数据保护的吗?
重要的一点是,数据保护系统并不是真正用于通用加密。我们希望你加密的东西,就其本质而言,有一个有限的生命周期,如身份验证令牌和密码重置令牌。
理论上,你可以对希望加密和长期存储的数据(例如在数据库中)使用数据保护系统。数据保护密钥每90天过期一次(默认情况下),但是你仍然可以使用过期的密钥解密数据。
如果数据保护密钥因为某种原因被删除,真正的危险就来了。不建议这样做,但意外总是会发生的。如果使用正确,删除数据保护密钥对大多数应用程序的影响相对较小——用户将不得不再次登录,以前发出的密码重置键将无效——这很烦人,但不会造成灾难。
另一方面,如果你已经用数据保护系统加密了敏感数据,然后将其存储在数据库中,那么就有大问题了。那些数据都不见了,被毁了。绝对不值得冒这个险!相反,你应该使用.NET Core中的专用加密库,以及为此目的创建的特定证书或密钥。
如何在我的ASP.NET Core中配置数据保护?
通常,你与数据保护系统交互的唯一地方是配置它的时候,如果没有正确地配置它,你可能会暴露于安全漏洞中,或者无法解密身份验证cookie。
一方面,数据保护系统需要易于配置和维护,因为复杂性和维护开销通常会导致bug或不良实践。但ASP.NET Core还需要在各种环境下运行:Windows、Linux、macOS;在Azure, AWS;在高端服务器和树莓派上。每个平台都有不同的内置加密机制和可用特性,而.NET Core需要在所有这些平台上都是安全的。
为了解决这个问题,数据保护系统使用了一种通用的“插件”式架构。基本上有两个不同的可插入区域:
- 密钥环持久性位置:密钥应该存储在哪里?
- 持久性加密:密钥是否应该在静止时加密,如果是,如何加密。
ASP.NET Core试图在默认情况下将这些设置为合理的选项。例如,在Windows(非azure应用程序)机器上,将持久化到%LOCALAPPDATA%\ASP.net\数据加密密钥。
不幸的是,一旦你开始在生产环境中运行应用程序并对应用程序进行扩展,大多数默认设置都将不起作用。相反,你可能需要研究一种可选的配置方法。
总结
在这篇文章中,我提供了ASP.NET Core数据保护系统的高级概述。我描述了数据保护系统的动机以及它背后的一些设计原则。
欢迎关注我的公众号,如果你有喜欢的外文技术文章,可以通过公众号留言推荐给我。
原文链接:https://andrewlock.net/an-introduction-to-the-data-protection-system-in-asp-net-core/