Powershell:安全地解码SecureString

时间:2018-02-19 11:50:40

标签: powershell securestring

请就这两个脚本的安全性提出专家意见:

[注意:这两个脚本的输出将是流水线的。它们不会被分配给任何变量。"]

首先:

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并不安全,因为它首先将securestring转换为内存,许多人指出我使用编组。所以,我已经构建了上述两个脚本作为试用版,我想知道这两个脚本中是否有任何鲁莽的操作。

修改

我已经更新了我的第二个字符串,通过实现:

来清理BSTR
finally{
    if ( $bstr -ne [IntPtr]::Zero ) {
  [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) #Frees the BSTR.
    }
}

但是,在管道中捕获的返回值似乎根本不安全,因为它在内存中也是如此,直到它被清理。

[注意:我还没有编写接受流水线值的脚本。]

使用securestring的重点似乎是通过将其解密回明文来销毁。好像我们永远不应该解密securestring。如果我错了,请纠正我。

1 个答案:

答案 0 :(得分:0)

所选择的解密技术无关紧要,因为您仍在转换为纯文本。

即使秘密在内存中只存在很短的时间,但是什么阻止我使用调试技术从内存中读取它?

  • PowerShell有一个集成的调试器,可以进入代码并检查变量(Wait-Debugger)。

  • 使用变量,参数或管道输出的脚本可以通过使用aliassses或其他模拟技术覆盖/重新定义命令行开关来拦截。

  • 您也容易受到意外披露的影响,例如,当您传递密码的脚本在使用-Verbose等时记录它时。

在此aspet中使用管道或直接变量并不重要。这两者本身都不是更安全,都要求/导致在内存中以明文形式保密。

我会寻找一个选项来指定加密到目标的秘密值,完全不需要解密。