在 Windows 命令中使用密码参数是否安全?
Is it secure to use a password argument in a Windows command?
假设我们有一个可以接受密码(或其他敏感信息)参数的程序或脚本:
> program.exe /password:secret
对于 Linux,最佳做法通常建议 反对 直接在命令行上指定密码,因为存在潜在的安全问题(密码可以出现在 shell的历史文件和系统进程table):
$ ./program.sh --password 'secret' &
[1] 4152
$ cat /proc/4152/cmdline
/bin/sh./program.sh--passwordsecret
然而,在四处搜索时,我没有看到 Windows 同样强烈的推荐。
在为 Windows 编写程序和脚本时,除了命令行选项的参数外,我们是否应该提供另一种输入密码的方法,以避免无意中暴露密码?
this question 的答案表明,专用的密码输入提示通过防止肩窥来提高安全性。在 shell 的上下文和 Windows 管理进程的方式中,是否有任何其他方法可以利用命令字符串中的可见密码来证明编写备用输入法是合理的?
从将密码作为参数传递给程序的批处理文件或 PowerShell 脚本启动程序时,安全隐患是否会发生变化?
$password = # prompt for password
program.exe /password:$password
Edit - 我知道我们可能会将这个问题误解为基于意见,因为我提到 "best practices" 和 "recommendations" 来提供背景。但是,我寻求具体证据来证明密码在命令参数中如何容易受到攻击,并且 - 如果此假设有效 - 描述安全替代方案的具体示例或参考。
Windows 历史上不保存会话之间的命令历史记录,仅在会话内保存。对于命令提示符和 PowerShell 都是如此。
正如 Bill Stewart 指出的那样,Windows PowerShell 在 Windows 10 和 Windows 2016 上默认包含 PSReadline,它会保存会话之间的命令历史记录。您可以通过查看此处的文件来了解这一点:(Get-PSReadLineOption).HistorySavePath
.
但是即使它被设置为关闭,或者在 OS 没有提供该选项的版本上,这并不意味着输入明文密码作为参数是个好主意。
如果你必须提供它,你应该 也有办法让程序在 运行 时间提示。
对于 PowerShell 和其他 .Net 应用程序,您在接受明文密码时还有另一个问题:它们在内存中徘徊,没有明确清除它们的好方法。
这个问题有两个方面:字符串在 .Net 中是不可变的,这意味着您不能只用空值或随机字符修改字符串以在内存中清除它(您实际上将创建一个全新的字符串),并且最重要的是,您无法控制垃圾回收何时处理特定对象,因此您无法显式删除它。
这就是 SecureString
class 存在的原因,但不是所有东西都可以使用它。
在 PowerShell 中,有一个 PSCredential
object,它以明文形式存储用户名,并以 SecureString
形式存储密码。这应该始终在 PowerShell 中使用,并且应该是首选参数类型(代替单独的用户名和密码)。
PowerShell 中大多数需要凭据的命令都将其视为此类对象。
您也可以使用此对象轻松检索明文版本的密码。这样做然后将其放入托管字符串中,您将面临我上面提到的风险。
不过在我看来,在这些情况下使用 PSCredential
对象仍然更可取,直到您需要明文版本为止。它有助于在内置/'official' 容量以及用户定义的命令中保持这种类型的标准化。
这种类型也很容易用 Export-Clixml
into a form that is encrypted. 序列化。
为了更直接地回答我的问题,这里对briantist的优秀回答做一个小小的补充:
当存在安全问题时,不要输入或请求密码或其他敏感数据作为命令行参数。其他用户和程序可以相当简单地窥探命令行参数。
我们可以使用Windows Management Instrumentation to pull command-line arguments in PowerShell and through other programs like those built on .NET。下面是一个使用 PowerShell 的示例:
PS> Get-WmiObject Win32_Process -Filter 'Name = "program.exe"' | Select-Object CommandLine
C:\program.exe /password:secret
命令行密码参数在任务管理器中对于同一系统上可以看到其他用户进程的任何用户也是可见的:
正如 briantist 在他的回答中所写,我们编写的程序和脚本应该提供除命令行参数之外的替代方法来输入敏感信息。 PowerShell 脚本可以使用 PSCredential
或 SecureString
对象在脚本之间安全地传递此信息。
假设我们有一个可以接受密码(或其他敏感信息)参数的程序或脚本:
> program.exe /password:secret
对于 Linux,最佳做法通常建议 反对 直接在命令行上指定密码,因为存在潜在的安全问题(密码可以出现在 shell的历史文件和系统进程table):
$ ./program.sh --password 'secret' &
[1] 4152
$ cat /proc/4152/cmdline
/bin/sh./program.sh--passwordsecret
然而,在四处搜索时,我没有看到 Windows 同样强烈的推荐。
在为 Windows 编写程序和脚本时,除了命令行选项的参数外,我们是否应该提供另一种输入密码的方法,以避免无意中暴露密码?
this question 的答案表明,专用的密码输入提示通过防止肩窥来提高安全性。在 shell 的上下文和 Windows 管理进程的方式中,是否有任何其他方法可以利用命令字符串中的可见密码来证明编写备用输入法是合理的?
从将密码作为参数传递给程序的批处理文件或 PowerShell 脚本启动程序时,安全隐患是否会发生变化?
$password = # prompt for password
program.exe /password:$password
Edit - 我知道我们可能会将这个问题误解为基于意见,因为我提到 "best practices" 和 "recommendations" 来提供背景。但是,我寻求具体证据来证明密码在命令参数中如何容易受到攻击,并且 - 如果此假设有效 - 描述安全替代方案的具体示例或参考。
Windows 历史上不保存会话之间的命令历史记录,仅在会话内保存。对于命令提示符和 PowerShell 都是如此。
正如 Bill Stewart 指出的那样,Windows PowerShell 在 Windows 10 和 Windows 2016 上默认包含 PSReadline,它会保存会话之间的命令历史记录。您可以通过查看此处的文件来了解这一点:(Get-PSReadLineOption).HistorySavePath
.
但是即使它被设置为关闭,或者在 OS 没有提供该选项的版本上,这并不意味着输入明文密码作为参数是个好主意。
如果你必须提供它,你应该 也有办法让程序在 运行 时间提示。
对于 PowerShell 和其他 .Net 应用程序,您在接受明文密码时还有另一个问题:它们在内存中徘徊,没有明确清除它们的好方法。
这个问题有两个方面:字符串在 .Net 中是不可变的,这意味着您不能只用空值或随机字符修改字符串以在内存中清除它(您实际上将创建一个全新的字符串),并且最重要的是,您无法控制垃圾回收何时处理特定对象,因此您无法显式删除它。
这就是 SecureString
class 存在的原因,但不是所有东西都可以使用它。
在 PowerShell 中,有一个 PSCredential
object,它以明文形式存储用户名,并以 SecureString
形式存储密码。这应该始终在 PowerShell 中使用,并且应该是首选参数类型(代替单独的用户名和密码)。
PowerShell 中大多数需要凭据的命令都将其视为此类对象。
您也可以使用此对象轻松检索明文版本的密码。这样做然后将其放入托管字符串中,您将面临我上面提到的风险。
不过在我看来,在这些情况下使用 PSCredential
对象仍然更可取,直到您需要明文版本为止。它有助于在内置/'official' 容量以及用户定义的命令中保持这种类型的标准化。
这种类型也很容易用 Export-Clixml
into a form that is encrypted.
为了更直接地回答我的问题,这里对briantist的优秀回答做一个小小的补充:
当存在安全问题时,不要输入或请求密码或其他敏感数据作为命令行参数。其他用户和程序可以相当简单地窥探命令行参数。
我们可以使用Windows Management Instrumentation to pull command-line arguments in PowerShell and through other programs like those built on .NET。下面是一个使用 PowerShell 的示例:
PS> Get-WmiObject Win32_Process -Filter 'Name = "program.exe"' | Select-Object CommandLine
C:\program.exe /password:secret
命令行密码参数在任务管理器中对于同一系统上可以看到其他用户进程的任何用户也是可见的:
正如 briantist 在他的回答中所写,我们编写的程序和脚本应该提供除命令行参数之外的替代方法来输入敏感信息。 PowerShell 脚本可以使用 PSCredential
或 SecureString
对象在脚本之间安全地传递此信息。