我没有成功让以下代码片段输出“Hello World!”在 PS7
$string = $("Hello World!" | ConvertTo-SecureString -AsPlainText -Force)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($string))
上面的代码是一个不指定长度解密安全字符串的例子。
相同的代码适用于 PS6 和 PS5 以完全解密安全字符串,但不适用于 PS7。我发现解决这个问题的唯一方法是使用 PtrToStringBSTR。然后它可以在此用例的所有 PS 版本中按预期工作。
我在 Github 上的 Powershell 存储库中提出了一个问题,但没有任何回应。老实说,我只是想确认其他人的行为是否相同。
https://github.com/PowerShell/PowerShell/issues/11953
我认为对于许多移植到 PS7 的代码来说,这样的事情将是一个突破性的变化。
这是我迄今为止发现的:
文档
https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.ptrtostringauto?view=netframework-4.8
根据文档,指定整数时,PtrToStringAuto:
Allocates a managed String and copies the specified number of characters from a string stored in unmanaged memory into it.
指定 11 的 int 返回“Hello”,这是因为返回的所有其他字符都是 Null。在这种情况下,您必须指定一个 23 的 int 以返回完整的字符串“Hello World!”使用这种方法。我已经将输出存储在一个变量中来演示这一点。
$String = $("Hello World!" | ConvertTo-SecureString -AsPlainText -Force)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($string), 23)
$String[0] Returns H
$String[1] Returns NULL
$String[2] Returns E
$String[3] Returns NULL
etc....
如果没有指定整数,PtrToStringAuto:
Allocates a managed String and copies all characters up to the first null character from a string stored in unmanaged memory into it.
我相信这表明安全字符串被存储为 NULL 值,而在 PS6 中它不是,或者 PtrToStringAuto 函数的行为已经改变,现在遵循上述文档描述的行为。
这只是 macOS 上的问题;但是,使用 PtrToStringBSTR 代替 PtrToStringAuto 来解密安全字符串可以在 Windows 和 macOS 上按预期工作。
这似乎相关:https://stackoverflow.com/a/11022662/4257163
我也没有看到任何地方进行了更改。
最佳答案
请注意 [securestring]
是 not recommended for new code再 .
虽然 Windows 上的安全字符串提供有限的保护 - 通过将加密的字符串存储在内存中 - 通过 DPAPI - 并通过缩短纯文本表示保存在内存中的窗口,在类 Unix 平台上根本不使用加密 .[1]
The only way around this I have found is to use
PtrToStringBSTR
.
这不仅是解决问题的方法,
PtrToStringBSTR
是应该用于开头的方法 ,假设输入字符串是 BSTR
.[2]请注意 将安全字符串与常规字符串相互转换
[string]
实例违背了使用 [securestring]
的目的从 开始:您最终将在您无法控制的进程内存中以纯文本形式表示您的敏感数据。如果你真的想这样做,一个更简单的、跨平台兼容的方法是:
[System.Net.NetworkCredential]::new('dummy', $string).Password
[1] 当您通过
ConvertFrom-SecureString
在文件中保存安全字符串时,这尤其成问题。或 Export-CliXml
- 见 this answer .[2]
Auto
在 PtrToStringAuto()
意味着假定非托管输入字符串使用适合平台的字符编码,而 BSTR
是所有平台上的“Unicode”(UTF-16)字符串。 在 Windows 上,假定非托管字符串具有 UTF-16 编码(这就是代码有效的原因),而在类 Unix 平台上,它是 UTF-8,因为 .NET Core 3.0(PowerShell [Core] 7.0 基于 .NET核心 3.1) ,这解释了您的症状:
NUL
字符。在 BSTR
当(错误)解释为 UTF-8 时,实例的 UTF-16 代码单元本身就被解释为字符。请注意 .NET Core 2.x(这是 PowerShell [Core] 6.x 所基于的)(不恰本地)默认为 UTF-16 , 其中 this PR fixed ,相当于一个突破性的变化。
关于powershell - 您能否在 macOS 上的 Powershell 7 中使用 PtrToStringAuto 来解密安全字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60404847/