【发布时间】:2021-01-09 01:16:03
【问题描述】:
我需要在 IIS 中运行 ASP.NET Core 2.2 的 Web 服务器上对 PDF 文档进行数字签名。 Web 应用程序与服务用户一起运行,模拟应在代码中完成。问题是,我无法通过 X509Store 类访问用户证书。我尝试创建一个仅模拟不同用户并在控制台中输出证书的最小示例。我以管理员身份运行它,但没有找到任何证书。
我在“计算机配置 > Windows 设置 > 安全设置 > 本地策略 > 用户权限管理”下的“本地组策略编辑器”(gpedit.msc) 中授予的权限:
- 作为操作系统的一部分:添加了 ServiceUser
- 允许本地登录:添加了 UserToBeImpersonated
- 作为批处理作业登录:添加了 UserToBeImpersonated
- 创建令牌对象:添加了 ServiceUser
- 替换进程级别令牌:添加了 ServiceUser
- 调整进程的内存配额:添加了 ServiceUser
对于模拟,我使用了来自 https://github.com/mj1856/SimpleImpersonation 的 SimpleImpersonation 并将其扩展为还加载用户配置文件,如下所示:
public static void RunAsUser(UserCredentials credentials, LogonType logonType, Action action)
{
// this method tells Windows to dynamically determine where to look for the HKEY_CURRENT_USER registry hive,
// rather than using the cached location from when the process was initially invoked
RegDisablePredefinedCache();
using (var tokenHandle = credentials.Impersonate(logonType))
using (var profileToken = credentials.ImpersonateUserProfile(tokenHandle.DangerousGetHandle()))
{
RunImpersonated(tokenHandle, _ => action());
}
}
internal UserProfileToken ImpersonateUserProfile(IntPtr tokenHandle)
{
var tokenDuplicate = IntPtr.Zero;
// Not sure if the token needs to be duplicated or not
if (DuplicateToken(tokenHandle, 2, ref tokenDuplicate) == 0)
HandleError(tokenHandle);
// Load User profile
var profileInfo = new ProfileInfo();
profileInfo.dwSize = Marshal.SizeOf(profileInfo);
profileInfo.lpUserName = _username;
profileInfo.dwFlags = 1;
// LoadUserProfile() failed
if (!LoadUserProfile(tokenDuplicate, ref profileInfo))
HandleError(tokenDuplicate);
// LoadUserProfile() failed - HKCU handle was not loaded
if (profileInfo.hProfile == IntPtr.Zero)
HandleError(tokenDuplicate);
return new UserProfileToken() { ProfileInfo = profileInfo, Token = tokenDuplicate };
}
public class UserProfileToken : IDisposable
{
public ProfileInfo ProfileInfo { get; set; }
public IntPtr Token { get; set; }
~UserProfileToken()
{
Dispose();
}
private bool isDisposed = false;
public void Dispose()
{
if (isDisposed) return;
isDisposed = true;
UnloadUserProfile(Token, ProfileInfo.hProfile);
}
}
[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);
[DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool UnloadUserProfile(IntPtr hToken, IntPtr lpProfileInfo);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegDisablePredefinedCache();
测试的主要代码如下:
var credentials = new Impersonator.UserCredentials(domain, username, password);
Impersonator.RunAsUser(credentials, Impersonator.LogonType.Interactive, () =>
{
Console.WriteLine($"Current user: {WindowsIdentity.GetCurrent().Name}");
var store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
if (store.Certificates.Count == 0)
{
Console.WriteLine("No Certificates found.");
}
else
{
var certCount = 0;
foreach (var cert in store.Certificates)
{
Console.WriteLine($"[{certCount}] Subject: {cert.Subject}");
Console.WriteLine($"[{certCount}] Issuer: {cert.Issuer}");
certCount++;
}
}
});
很遗憾,当相同的代码(没有模拟)在目标用户机器上显示两个证书时,找不到任何证书。
我在服务器上发现的另一个有趣的事情是C:\Users
【问题讨论】:
标签: c# asp.net-core certificate x509 impersonation