问题
Imagine that we have a program or script that can take a password (or other sensitive information) argument:
> program.exe /password:secret
For Linux, best practice generally recommends against specifying the password directly on the command-line because of potential security concerns (the password can appear in the shell's history file and the system's process table):
$ ./program.sh --password 'secret' &
[1] 4152
$ cat /proc/4152/cmdline
/bin/sh./program.sh--passwordsecret
However, when searching around, I don't see the same vigorous recommendation for Windows.
When writing programs and scripts for Windows, should we provide an alternate means to input a password besides an argument to a command-line option to avoid unintentionally exposing the password?
The answer to this question suggests that a dedicated password input prompt improves security by preventing shoulder-surfing. Are there any other ways to exploit a visible password in a command string that justifies writing alternate input methods, both in the context of a shell and in the way Windows manages processes?
Do the security implications change when starting a program from a batch file or PowerShell script that passes a password as an argument to the program?
$password = # prompt for password
program.exe /password:$password
Edit - I understand that we can misinterpret this question as opinion-based because I mention "best practices" and "recommendations" to provide background. However, I seek specific evidence that demonstrates how a password might be vulnerable in a command argument and—if this assumption is valid—concrete examples or references that depict secure alternatives.
回答1:
Windows historically didn't save command history between sessions, only within the session. This was true for the command prompt and for PowerShell.
As Bill Stewart pointed out, Windows PowerShell on Windows 10 and Windows 2016 includes PSReadline by default, which does save your command history between sessions. You can see this by looking at the file here: (Get-PSReadLineOption).HistorySavePath
.
But even if it's set to off, or on an OS version that didn't offer the option, that doesn't mean entering a plaintext password as an argument is a good idea.
If you must offer that, you should also have a way to have the program prompt at run time.
For PowerShell and other .Net applications, you have another issue with accepting plaintext passwords: they linger in memory and there's no good way to explicitly clear them.
This issue is two-fold: strings are immutable in .Net, which means you cannot just modify the string with nulls or random characters to clear it in memory (you will actually be creating a brand new string), and on top of that you cannot control when a specific object will handled by garbage collection, so you can't explicitly remove it.
This is why the SecureString class exists, but not everything can use this.
In PowerShell, there is a PSCredential object which stores a user name in plain text and a password as a SecureString
. This should always be used in PowerShell, and should be the preferred argument type (in lieu of a separate user name and password).
Most commands in PowerShell that require a credential take it as this type of object.
You can retrieve a plaintext version of the password easily with this object as well. Doing so then puts that into a managed string and you get the risks I mentioned above.
In my opinion though, it is still preferable to use a PSCredential
object in these situations, right up until the point you need the plaintext version. It helps to maintain the standardization of this type in both a built-in/'official' capacity, as well as in user-defined commands.
This type is also easily serializable with Export-Clixml into a form that is encrypted. This can give you a really nice way of providing an automated option to use stored credentials in scripts, with nothing in plaintext, and no prompting or user intervention required.
回答2:
To more directly answer my question, here's a small supplement to briantist's excellent answer:
When security is a concern, do not input or request passwords or other sensitive data as command-line arguments. Other users and programs can snoop on command-line arguments fairly trivially.
We can use Windows Management Instrumentation to pull command-line arguments in PowerShell and through other programs like those built on .NET. Here's an example using PowerShell:
PS> Get-WmiObject Win32_Process -Filter 'Name = "program.exe"' | Select-Object CommandLine
C:\program.exe /password:secret
The command-line password argument is also visible in the Task Manager for any users on the same system that can see processes from other users:
As briantist wrote in his answer, programs and scripts that we write should provide alternate means to input sensitive information besides command-line arguments. PowerShell scripts can securely pass this information between scripts using PSCredential
or SecureString
objects.
来源:https://stackoverflow.com/questions/47041712/is-it-secure-to-use-a-password-argument-in-a-windows-command