自定义凭据提供程序加载异常:RDP登录下OTP/一次性令牌方案受阻
解决方案:自定义凭据提供程序RDP登录问题
问题根源
这个问题确实由远程Windows机器的Winlogon凭据验证机制导致:当初始用户名/密码验证失败时,Winlogon会终止当前自定义凭据提供程序实例,并默认 fallback 到系统默认凭据提供程序,导致你的OTP/推送验证流程无法触发。
一、临时注册表绕过方案(仅用于测试)
1. 调整凭据提供程序加载优先级
打开注册表编辑器,定位到:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers
找到你的自定义凭据提供程序的CLSID项,将其默认字符串值(格式为{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX})调整到系统默认凭据提供程序(如密码凭据提供程序CLSID:{60b78e88-ead8-445c-9cfd-0b87f74ea6cd})之前。
同时修改Winlogon下的凭据加载列表:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
修改CredentialProviders字符串值,将你的CLSID放在最前面,示例:
{你的CLSID}, {60b78e88-ead8-445c-9cfd-0b87f74ea6cd}
2. 临时禁用凭据过滤器
定位到凭据过滤器注册表项:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Provider Filters
找到你的自定义过滤器项,添加或修改Disabled DWORD值为1,临时禁用过滤器以强制加载你的凭据提供程序。注意:生产环境禁用过滤器会破坏安全策略,仅用于测试验证。
二、永久解决方案:COM组件/凭据提供程序改造
1. 修改现有凭据提供程序逻辑
不要依赖初始凭据的验证结果决定是否加载。在你的凭据提供程序实现中:
- 重写
ICredentialProvider::GetCredentialCount和ICredentialProvider::GetCredentialAt方法,无论初始用户名/密码是否正确,始终返回你的OTP/推送验证界面。 - 在
ICredentialProvider::SetUsageScenario方法中,针对CREDENTIAL_PROVIDER_USAGE_SCENARIO_LOGON和CREDENTIAL_PROVIDER_USAGE_SCENARIO_REMOTE_LOGON场景,强制显示你的验证UI,拒绝 fallback 到系统默认界面。
2. COM钩子拦截LSA验证流程
编写COM组件挂钩系统验证逻辑,对接你的Web服务做一次性令牌验证:
- 实现
ICredentialProviderFilter接口,调整过滤规则,确保你的凭据提供程序在所有登录场景下(包括初始凭据验证失败时)都能被加载。 - 使用钩子工具(如MinHook)挂钩
LsaLogonUser或WTSLogonUser函数,当检测到RDP登录请求时:- 拦截默认的密码验证流程;
- 调用你的Web服务验证一次性令牌;
- 验证通过后,构造合法的登录上下文返回给Winlogon,完成登录。
关键注意事项
- 所有COM组件和凭据提供程序必须以系统权限运行,且需要数字签名才能被Winlogon加载;
- 测试时优先在本地虚拟机验证,避免影响生产环境;
- 严格遵循Windows Credential Provider Framework规范,适配不同登录场景(本地、远程、锁屏等)。
内容的提问来源于stack exchange,提问作者Joseph Willcoxson
相关产品推荐
相关产品推荐

