【发布时间】:2018-02-19 11:50:40
【问题描述】:
请就这两个脚本的安全性发表您的专家意见:
[注意:这两个脚本的输出将被管道化。它们不会被分配给任何变量。"]
第一:
Function GetFrom-SecureString([SecureString]$SecureString) {
[IntPtr]$valuePtr = [IntPtr]::Zero
try {
$valuePtr = [Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($SecureString)
return [Runtime.InteropServices.Marshal]::PtrToStringUni($valuePtr);
}
finally {
[Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($valuePtr);
}
}
第二:
Function Decode-SecureString([SecureString]$SecureString){
try{
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
$length = [Runtime.InteropServices.Marshal]::ReadInt32($bstr, -4)
for ( $i = 0; $i -lt $length; ++$i ) {
[CHAR][Runtime.InteropServices.Marshal]::ReadByte($bstr, $i)
}
}
finally{
if ( $bstr -ne [IntPtr]::Zero ) {
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
}
}
}
我知道使用$cred.GetNetworkCredential().Password 是不安全的,因为它首先将安全字符串转换为内存,并且许多人向我指出要使用编组。所以,我把上面的两个脚本构建为试用版,我想知道这两个脚本是否有什么鲁莽的操作。
编辑:
我已经更新了我的第二个字符串以通过实施来清理 BSTR:
finally{
if ( $bstr -ne [IntPtr]::Zero ) {
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) #Frees the BSTR.
}
}
但是,在管道中捕获的返回值似乎根本不安全,因为它也在内存中,直到它被清理。
[注意:我还没有编写将接受流水线值的脚本。]
使用安全字符串的意义似乎被解密回明文破坏了。好像我们永远不应该解密安全字符串。如果我错了,请纠正我。
【问题讨论】:
-
请详细解释您所说的“更安全”是什么意思。
-
他们仍然将 SecureString 转换为内存......不可能不发生这种情况。你的策略应该是确保一旦不再需要它就从内存中删除。为此,我建议选项 1,但由于它是一个函数,您可能会在某处捕获输出,因此返回的值可能会存在于某处,直到它被垃圾收集
-
@arco444 你的策略应该是确保一旦不再需要它就从内存中删除。为此,我建议选项 1 选项 1 创建不可变的托管
string对象。您如何建议将其从内存中删除? -
解密
SecureString的问题是你不能在这样做之后强行覆盖内存中的纯文本String副本(它是一个托管的String对象)。如果您确实需要将SecureString解密为纯文本,那么这是您将不得不忍受的限制。