使用SecureString与LogonUser函数

6
为了学习目的,我正在编写自己的Active Directory客户端。为了执行诸如解锁帐户和重置密码之类的命令,我必须输入我的管理员帐户和密码,并使用WindowsIdentity.Impersonate以我的管理员帐户运行代码。我想知道保护密码的选项,因为它必须在程序中多次使用。
据我所知,我可以使用SecureString来存储密码。但是要以我的管理员帐户运行代码,我必须使用WindowsIdentity.Impersonate,而要使用它,我必须从LogonUser获取一个令牌,该令牌需要常规的string而不是SecureString
所以我必须:
  1. 启动时登录

  2. 将输入转换为SecureString

  3. 清除输入

然后稍后当我想要执行需要提升权限的功能时:
  1. 将先前创建的SecureString转换为string

  2. 将转换后的字符串传递给LogonUser

  3. 将转换的字符串清除为null

  4. 执行命令

  5. 清除LogonUser对象

这是正确的方法吗?不需要将SecureString转换为string使用它似乎很奇怪......似乎会削弱其目的并在我转换它时使密码更加易受攻击。
编辑:修复了LogonUser的名称

1
你说得对,转换为字符串会失去意义。UserImpersonation是什么?它是否PInvoke到Win32 API?您可能需要更改它使用的函数以传递IntPtr而不是字符串。 - Ilian
哦,抱歉...我会修正我的问题。是的,UserImpersonation是我很久以前写的一个类...它基本上是LogonUser的一个包装器,它还请求一个字符串作为密码。那能改成IntPtr吗?如果是这样,我可以将SecureString传递给密码参数吗?(我现在想试试,但我已经不在工作中了...) - duck
1
不,你不能直接使用SecureString,但是安全地传递密码不应该很困难。我下面会回答... - Ilian
1个回答

8
在您的UserImpersonation类中,更改您声明LogonUser时使用IntPtr而不是string作为密码。
关于Marshal.SecureStringToGlobalAllocUnicode的代码示例恰好包含您需要的内容。这里是相关片段:
[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);

...

IntPtr tokenHandle = IntPtr.Zero;

IntPtr passwordPtr = IntPtr.Zero;

try
{
    // Marshal the SecureString to unmanaged memory.
    passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);

    returnValue = LogonUser(userName, domainName, passwordPtr,
                            LOGON32_LOGON_INTERACTIVE,
                            LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

 }
 finally
 {
     // Zero-out and free the unmanaged string reference.
     Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);

     // Close the token handle.
     CloseHandle(tokenHandle);
 }

完美!谢谢! :) - duck
@duckwizzle 不用担心 - Ilian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接