在.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. SpringBoot2 整合Nacos组件,环境搭建和入门案例详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Nacos基础简介 1.概念简介 Nacos 是构建以"服务"为中心的现代应用架构,如微服务范式.云原生范式等服务基础 ...

  2. 每天玩转3分钟 MyBatis-Plus - 2. 普通查询

    每天玩转3分钟 MyBatis-Plus - 1. 配置环境 每天玩转3分钟 MyBatis-Plus - 2. 普通查询 mybatis-plus的查询功能非常强大, 这一篇,我们来看下mybati ...

  3. ls命名 | Linux统计文件夹内的文件个数

    ls命名 man ls -R 递归列出全部的目录内容 recusive -a 列出所有的文件(包括以 . 开头的隐藏文件) all -r 逆序排列 reverse -t 按照时间信息排序 time - ...

  4. idea搭建springmvc(maven版)

    一.创建maven项目 (1)选择 file > new > project (2)填写对应信息,一路点击next 配置自己本地的maven,继续next 命名项目名(随意写,但要易懂), ...

  5. Windows PHP 开启opcache的方法

    PHP opcache可以提升性能.Windows PHP 配置 opcache 的方法如下: 1.先检查PHP目录下ext目录中有没有php_opcache.dll,没有的话自己下载(PHP 5.5 ...

  6. mysql数据库my.ini配置文件中文详解

    mysql数据库my.ini配置文件中文详解 mysqld程序–目录和文件 basedir = path 使用给定目录作为根目录(安装目录). character-sets-dir = path 给出 ...

  7. CTF--HTTP服务--SQL注入-X-Forwarded-For报文头

    开门见山 1. 扫描靶场ip,发现PCS 192.168.31.196 2. 扫描靶场开放服务信息 3. 扫描靶场全部信息 4. 探测敏感信息 5. 查看靶场80端口的主界面 6. 使用AVWS工具进 ...

  8. day04_IDEA、方法

    day04_IDEA.方法 1.快捷输入 psvm:public static void main(String[] args){ } sout:System.out.print("&quo ...

  9. systemctl中添加mysql服务

    由于mysql的版本更新,许多术语有了新含义,所以需要特别指出,mysqld.service 等价于mysqld vim /usr/lib/systemd/system/mysqld.service ...

  10. 手把手写框架入门(一) | 核心拦截器DispatchFilter实现

    前言 1Filter实现框架拦截 1配置自定义Filter 2创建一个Filter 3创建一个ActionMapping 4创建一个ActionMapper 5创建一个WebExecutor 6创建测 ...