C# 调用登录用户因安全字符串而失败

本文关键字:字符串 失败 安全 调用 登录 用户 | 更新日期: 2023-09-27 18:37:25

大家,我遇到了LogonUser函数的问题。

只想知道我是否可以通过这个签名将LogonUser函数导入 C#:

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int LogonUser(string username, string domain, IntPtr password, int logonType, int logonProvider, ref IntPtr token);

因为我想保护我的密码不是使用字符串,而是使用SecureString类。然后稍后使用该函数,如下所示:

var passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
var result = LogonUser(userName, domain, passwordPtr, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);

我总是得到结果= 0,并且消息显示用户名和密码不正确。但是当我将签名更改为使用字符串密码时,一切正常。

请帮助我保护密码SecureString对我来说很重要。

C# 调用登录用户因安全字符串而失败

正如 Alex K 所指出的,有一个在SecureStringToGlobalAllocUnicode中使用LogonUser的例子。请注意,P/Invoke 声明有:

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String username, String domain, IntPtr password,
            int logonType, int logonProvider, ref IntPtr token);

并且已经指定了该CharSet = CharSet.Unicode。不幸的是,由于历史原因,默认CharSet值是Ansi,所以这就是你的 P/Invoke 尝试将使用的值。

这对于 username 参数很好,因为 P/Invoke 基础结构将确保它正确转换string。但它不适合password参数,因为您已经执行了字符串转换,并且已经将其作为 Unicode 完成 - 而 P/Invoke 现在看到的只是一个IntPtr

我建议更新您的 P/Invoke 签名以匹配示例中给出的签名。


另一种选择是切换到使用 SecureStringToGlobalAllocAnsi 并保留您的 P/Invoke 签名。但这是一个非常二流的解决方案。在 2015 年编写非 Unicode 感知代码是非常不推荐的。

只要养成在你编写的任何 P/Invoke 签名中始终指定CharSet.Unicode的习惯。