在Windows命令中使用密码参数是否安全?

Cy *_*nol 2 windows security shell powershell windows-scripting

想象一下,我们有一个可以获取密码(或其他敏感信息)参数的程序或脚本:

> program.exe /password:secret
Run Code Online (Sandbox Code Playgroud)

对于Linux,最佳实践通常建议不要直接在命令行上指定密码,因为存在潜在的安全问题(密码可以出现在shell的历史文件和系统的进程表中):

$ ./program.sh --password 'secret' &
[1] 4152

$ cat /proc/4152/cmdline 
/bin/sh./program.sh--passwordsecret
Run Code Online (Sandbox Code Playgroud)

但是,在搜索时,我没有看到针对Windows的强烈建议.

在为Windows编写程序和脚本时,我们是否应该提供另一种方法来输入除命令行选项的参数之外的密码,以避免无意中泄露密码?

这个问题的答案表明,专用的密码输入提示可以防止肩膀冲浪,从而提高安全性.有没有其他方法可以在命令字符串中利用可见密码来证明编写备用输入方法,无论是在shell的上下文中还是在Windows管理进程的方式中?

从批处理文件或PowerShell脚本启动程序时,安全隐患是否会发生变化,该脚本将密码作为参数传递给程序?

$password = # prompt for password 
program.exe /password:$password
Run Code Online (Sandbox Code Playgroud)

编辑 - 我理解我们可以将这个问题误解为基于意见的问题,因为我提到"最佳实践"和"建议"来提供背景知识.但是,我寻求具体的证据来证明密码在命令参数中可能容易受到攻击,并且 - 如果这个假设是有效的 - 具体示例或描述安全备选方案的参考.

bri*_*ist 7

Windows历史上不会在会话之间保存命令历史记录,仅在会话中保存.这对于命令提示符和PowerShell都是如此.

正如Bill Stewart指出的那样,Windows 10和Windows 2016上的Windows PowerShell默认包含PSReadline,它会在会话之间保存命令历史记录.您可以通过在文件看这里看到这一点:(Get-PSReadLineOption).HistorySavePath.

但即使它已经关闭,或者在没有提供选项的操作系统版本上,这并不意味着输入明文密码作为参数是一个好主意.

如果您必须提供,那么您还应该有一种方法可以在运行时提示程序.

对于PowerShell和其他.Net应用程序,您还有另一个接受明文密码的问题:它们会在内存中停留,并且没有明确清除它们的好方法.

这个问题有两个问题:字符串在.Net中是不可变的,这意味着你不能只修改带有空值或随机字符的字符串以在内存中清除它(你实际上将创建一个全新的字符串),除此之外你无法控制垃圾回收何时处理特定对象,因此无法显式删除它.

这就是这个SecureString存在的原因,但不是所有东西都可以使用它.

在PowerShell中,有一个PSCredential对象以纯文本形式存储用户名,密码用作SecureString.这应始终在PowerShell中使用,并且应该是首选参数类型(代替单独的用户名和密码).

PowerShell中需要凭据的大多数命令都将其视为此类对象.

您也可以使用此对象轻松检索密码的纯文本版本.这样做然后将其放入托管字符串中,您将获得我上面提到的风险.

在我看来,PSCredential在这些情况下使用对象仍然是可取的,直到您需要明文版本为止.它有助于在内置/"官方"容量以及用户定义的命令中维护此类型的标准化.

此类型也可以使用Export-Clixml加密的形式轻松序列化.这可以为您提供一种非常好的方式来提供自动选项,以便在脚本中使用存储的凭据,没有任何明文,也不需要提示或用户干预.

  • "Windows不会在会话之间保存命令历史记录" - 仅供参考,如果使用存储命令历史记录文件的PowerShell PSReadline模块(并且默认情况下在Windows 10/Server 2016上安装并激活PSReadline,并且可能更新),则不再是这种情况). (4认同)
  • 有趣.你确定吗?尝试运行`(Get-PSReadLineOption).HistorySavePath`. (3认同)
  • @Bill_Stewart谢谢你.设置路径,文件在那里,`.HistorySaveStyle`设置为`SaveIncrementally`,文件包含历史记录.当我关闭所有PowerShell窗口并重新打开它时,它确实有一些历史记录,但它根本不会回到很远的地方.最多一两天.历史也没有用'h`表示让我感到困惑.无论如何,我应该编辑这些东西. (3认同)
  • 并补充一下 Brian 所说的:我想这首先是创建“SecureString”的推动力的一部分。 (2认同)

Cy *_*nol 6

为了更直接地回答我的问题,这里是对briantist优秀回答的一个小补充:

当考虑安全性时,不要输入或请求密码或其他敏感数据作为命令行参数。其他用户和程序可以相当简单地窥探命令行参数。

我们可以使用Windows Management Instrumentation在 PowerShell 中以及通过其他程序(如基于 .NET 构建的程序)提取命令行参数。下面是一个使用 PowerShell 的示例:

PS> Get-WmiObject Win32_Process -Filter 'Name = "program.exe"' | Select-Object CommandLine

C:\program.exe /password:secret
Run Code Online (Sandbox Code Playgroud)

对于同一系统上可以查看其他用户进程的任何用户,命令行密码参数也在任务管理器中可见:

显示纯文本密码参数的任务管理器屏幕截图

正如 briantist 在他的回答中所写的那样,我们编写的程序和脚本应该提供替代方法来输入除了命令行参数之外的敏感信息。PowerShell 脚本可以使用PSCredentialSecureString对象在脚本之间安全地传递此信息。