在.NET Core中使用MachineKey

姐妹篇:《ASP.NET Cookie是怎么生成的》

姐妹篇:《.NET Core验证ASP.NET密码》

在上篇文章中,我介绍了Cookie是基于MachineKey生成的,MachineKey决定了Cookie生成的算法和密钥,并如果使用多台服务器做负载均衡时,必须指定一致的MachineKey

但在.NET Core中,官方似乎并没有提供MachineKey实现,这为兼容.NET FrameworkCookie造成了许多障碍。

今天我将深入探索MachineKey这个类,看看里面到底藏了什么东西,本文的最后我将使用.NET Core来解密一个ASP.NET MVC生成的Cookie

认识MachineKey

.NET Framework中,machineKey首先需要一个配置,写在app.config或者web.config中,格式一般如下:

<machineKey validationKey="128个hex字符" decryptionKey="64个hex字符" validation="SHA1" decryption="AES" />

网上能找到可以直接生成随机MachineKey的网站:https://www.developerfusion.com/tools/generatemachinekey/

MachineKeyvalidationKeydecryptionKey的内容只要符合长度和hex要求,都是可以随意指定的,所以machineKey生成器的意义其实不大。

探索MachineKey

打开MachineKey的源代码如下所示(有删减):

public static class MachineKey {
public static byte[] Unprotect(byte[] protectedData, params string[] purposes) {
// ...有删减 return Unprotect(AspNetCryptoServiceProvider.Instance, protectedData, purposes);
} // Internal method for unit testing.
internal static byte[] Unprotect(ICryptoServiceProvider cryptoServiceProvider, byte[] protectedData, string[] purposes) {
// If the user is calling this method, we want to use the ICryptoServiceProvider
// regardless of whether or not it's the default provider. Purpose derivedPurpose = Purpose.User_MachineKey_Protect.AppendSpecificPurposes(purposes);
ICryptoService cryptoService = cryptoServiceProvider.GetCryptoService(derivedPurpose);
return cryptoService.Unprotect(protectedData);
}
}

具体代码可参见:https://referencesource.microsoft.com/#system.web/Security/MachineKey.cs,209

可见它本质是使用了AspNetCryptoServiceProvider.Instance,然后调用其GetCryptoService方法,然后获取一个cryptoService,最后调用Unprotect,注意其中还使用了一个Purpose的类,依赖非常多。

AspNetCryptoServiceProvider

其中AspNetCryptoServiceProvider.Instance的定义如下(有删减和整合):

internal sealed class AspNetCryptoServiceProvider : ICryptoServiceProvider {
private static readonly Lazy<AspNetCryptoServiceProvider> _singleton = new Lazy<AspNetCryptoServiceProvider>(GetSingletonCryptoServiceProvider); internal static AspNetCryptoServiceProvider Instance {
get {
return _singleton.Value;
}
} private static AspNetCryptoServiceProvider GetSingletonCryptoServiceProvider() {
// Provides all of the necessary dependencies for an application-level
// AspNetCryptoServiceProvider. MachineKeySection machineKeySection = MachineKeySection.GetApplicationConfig(); return new AspNetCryptoServiceProvider(
machineKeySection: machineKeySection,
cryptoAlgorithmFactory: new MachineKeyCryptoAlgorithmFactory(machineKeySection),
masterKeyProvider: new MachineKeyMasterKeyProvider(machineKeySection),
dataProtectorFactory: new MachineKeyDataProtectorFactory(machineKeySection),
keyDerivationFunction: SP800_108.DeriveKey);
}
}

具体代码可见:https://referencesource.microsoft.com/#system.web/Security/Cryptography/AspNetCryptoServiceProvider.cs,68dbd1c184ea4e88

可见它本质是依赖于AspNetCryptoServiceProvider,它使用了MachineKeyCryptoAlgorithmFactoryMachineKeyMasterKeyProviderMachineKeyDataProtectorFactory,以及一个看上去有点奇怪的SP800_108.DeriveKey

AspNetCryptoServiceProviderGetCryptoService方法如下:

public ICryptoService GetCryptoService(Purpose purpose, CryptoServiceOptions options = CryptoServiceOptions.None) {
ICryptoService cryptoService;
if (_isDataProtectorEnabled && options == CryptoServiceOptions.None) {
// We can only use DataProtector if it's configured and the caller didn't ask for any special behavior like cacheability
cryptoService = GetDataProtectorCryptoService(purpose);
}
else {
// Otherwise we fall back to using the <machineKey> algorithms for cryptography
cryptoService = GetNetFXCryptoService(purpose, options);
} // always homogenize errors returned from the crypto service
return new HomogenizingCryptoServiceWrapper(cryptoService);
} private NetFXCryptoService GetNetFXCryptoService(Purpose purpose, CryptoServiceOptions options) {
// Extract the encryption and validation keys from the provided Purpose object
CryptographicKey encryptionKey = purpose.GetDerivedEncryptionKey(_masterKeyProvider, _keyDerivationFunction);
CryptographicKey validationKey = purpose.GetDerivedValidationKey(_masterKeyProvider, _keyDerivationFunction); // and return the ICryptoService
// (predictable IV turned on if the caller requested cacheable output)
return new NetFXCryptoService(_cryptoAlgorithmFactory, encryptionKey, validationKey, predictableIV: (options == CryptoServiceOptions.CacheableOutput));
}

注意其中有一个判断,我结合dnSpy做了认真的调试,发现它默认走的是GetNetFXCryptoService,也就是注释中所谓的<machineKey>算法。

然后GetNetFXCryptoService方法依赖于_masterKeyProvider_keyDerivationFunction用来生成两个CryptographicKey,这两个就是之前所说的MachineKeyMasterKeyProviderMachineKeyDataProtectorFactory

注意其中还有一个HomogenizingCryptoServiceWrapper类,故名思义,它的作用应该是统一管理加密解释过程中的报错,实际也确实如此,我不作深入,有兴趣的读者可以看看原始代码在这:https://referencesource.microsoft.com/#system.web/Security/Cryptography/HomogenizingCryptoServiceWrapper.cs,25

最后调用NetFXCryptoService来执行Unprotect任务。

NetFXCryptoService

这个是重点了,源代码如下(有删减):

internal sealed class NetFXCryptoService : ICryptoService {

    private readonly ICryptoAlgorithmFactory _cryptoAlgorithmFactory;
private readonly CryptographicKey _encryptionKey;
private readonly bool _predictableIV;
private readonly CryptographicKey _validationKey; // ...有删减 // [UNPROTECT]
// INPUT: protectedData
// OUTPUT: clearData
// ALGORITHM:
// 1) Assume protectedData := IV || Enc(Kenc, IV, clearData) || Sign(Kval, IV || Enc(Kenc, IV, clearData))
// 2) Validate the signature over the payload and strip it from the end
// 3) Strip off the IV from the beginning of the payload
// 4) Decrypt what remains of the payload, and return it as clearData
public byte[] Unprotect(byte[] protectedData) {
// ...有删减
using (SymmetricAlgorithm decryptionAlgorithm = _cryptoAlgorithmFactory.GetEncryptionAlgorithm()) {
// 省略约100行代码

在.NET Core中使用MachineKey的更多相关文章

  1. ASP.NET Core中的数据保护

    在这篇文章中,我将介绍ASP.NET Core 数据保护系统:它是什么,为什么我们需要它,以及它如何工作. 为什么我们需要数据保护系统? 数据保护系统是ASP.NET Core使用的一组加密api.加 ...

  2. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  3. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  4. Asp.net Core中使用Session

    前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...

  5. 在ASP.NET Core中使用百度在线编辑器UEditor

    在ASP.NET Core中使用百度在线编辑器UEditor 0x00 起因 最近需要一个在线编辑器,之前听人说过百度的UEditor不错,去官网下了一个.不过服务端只有ASP.NET版的,如果是为了 ...

  6. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  7. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  8. ASP.NET Core中的依赖注入(3): 服务的注册与提供

    在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...

  9. ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理

    ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...

随机推荐

  1. spring同时操作多数据库 多个mysql和mongoDB,不需切换数据源,同时操作mysql和mongodb

    源码:https://github.com/haihai1172/spring-mysql-mongoDB 项目目录 1.环境搭建,java-sdk 1.8 具体怎么搭建,就不说了 2.配置jdbc. ...

  2. MapGIS文件如何压缩存盘

    经过多次编辑修改的MapGIS数据,含有大量逻辑上已删除的节点或图元,数据冗余复杂, 在转换过程前应注意一定要采用压缩存盘方式处理,目的是确保编辑状态已删除的数据真正从物理存储层删除,以确保数据的精简 ...

  3. C#实现DataTable转为Excel文件

    实现DataTable转为Excel文件,和上次分享的Excel文件转为DataTable互为反操作.DataTable转化为Excel文件是通过传入一个DataTable类型的参数,然后将传入的Da ...

  4. Java 用集合实现简单的斗地主发牌

    创建数组.集合,存放数据 public class FightAgainstLandlords { /** * poker集合,存储54张牌 */ private ArrayList<Strin ...

  5. invalid expression: missing ) after argument list in xxx 或者 console.error(("[Vue warn]: " + msg + trace));

    效果图:   此处错误原因   中文输入法的 逗号 导致    :   解决方案: 改为 英文输入法的 逗号

  6. 想玩转JAVA高并发,这些概念你必须懂!

    我们在找工作时,经常在招聘信息上看到有这么一条:有构建大型互联网服务及高并发等经验,你第一时间想到的是媒体常说的双十一吗?带着问题,我们一起思考技术…. 高并发高并发 它是互联网分布式系统架构设计中必 ...

  7. Mysql.复选条件的查询

    场景:有筛选条件 联盟:1.复联 2.正义联盟 3.猛禽小队,条件可多选,求查询结果. name league 飞人 复联,正义联盟 黑人 复联,正义联盟,猛禽小队 打手枪的男人 复联,猛禽小队 深井 ...

  8. PlayCanvas PBR材质shader代码分析(vertex shader)

    顶点shader主要对顶点坐标变换,将顶点坐标从local->world->view->clip 空间变换 local空间:模型物体坐标系 world空间:世界空间坐标系 view空 ...

  9. 腾讯云ubuntu服务器无法以root身份ssh连接

    在腾讯云上拿到的Ubuntu主机分配给的用户是ubuntu用户,并不是root用户,而阿里云上拿到的Ubuntu主机分配给的用户就是root用户.如果没有root用户权限做事情会变得麻烦,每次做什么都 ...

  10. Macbook 安装 opencv(cv2) 及在pycharm 下的使用

    python和opencv的安装都很顺利,就是在PyCharm下的配置浪费了一点时间. 一.原料 1.max系统 2.python(本文用的版本是3.6.5) 3.opencv(本文中使用的版本是3. ...