Shell script password security of command-line parameters
Command lines will always be visible (if only through /proc).
So the only real solution is: don't. You might supply it on stdin, or a dedicated fd:
./my_secured_process some parameters 3<<< "b@dP2ssword"
with a script like (simplicity first)
#!/bin/bash
cat 0<&3
(this sample would just dump a bad password to stdout)
Now all you need to be concerned with is:
- MITM (spoofed scripts that eaves drop the password, e.g. by subverting PATH)
- bash history retaining your password in the commandline (look at HISTIGNORE for bash, e.g.)
- the security of the script that contains the password redirection
- security of the tty's used; keyloggers; ... as you can see, we have now descended into 'general security principles'
Is it secure to use a password argument in a Windows command?
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.
Passing values that the commands in a shell script are going to expect
You need to use the "expect" command to send password.
Refer this answer
using expect in bash script
Hiding secret from command line parameter on Unix
First, you can NOT hide command line arguments. They will still be visible to other users via
ps aux
andcat /proc/$YOUR_PROCESS_PID/cmdline
at the time of launching the program (before the program has a chance to do run-time changes to arguments). Good news is that you can still have a secret by using alternatives:Use standard input:
mySecret='hello-neo' printenv mySecret | myCommand
Use a dedicated file if you want to keep the secret detached from the main script (note that you'd be recommended to use full disc encryption and make sure the file has correct
chmod
permissions):cat /my/secret | myCommand
Use environment variables (with caveats). If your program can read them, do this:
mySecret='hello-neo' myCommand
Use temporary file descriptor:
myCommand <( mySecret='hello-neo' printenv mySecret )
In the last case your program will be launched like myCommand /dev/fd/67
, where the contents of /dev/fd/67
is your secret (hello-neo
in this example).
In all of the above approaches, be wary of leaving the command in bash command history (~/.bash_history
). You can avoid this by either running the command from a script (file), or by interactively prompting yourself for password each time:
read -s secret
s=$secret printenv s | myCommand # approach 2
myCommand <( s=$secret printenv s ) # approach 3
secret=$secret myCommand # approach 4
export secret && myCommand # another variation of approach 4
Sending passwords securely via command line without being exposed in ps/wmic (Windows,Unix)
This is not possible (at least not on Linux, in a reliable way) to pass program arguments securely.
A possible workaround is to pass the name of a file (or some other resource - e.g. some "reference" to some database entry) containing that password, or use some other inter-process communication facility (e.g. on Linux, fifo(7), shm_overview(7), pipe(7), unix(7), etc...) to pass these sensitive informations. You might also consider using environment variables (see environ(7) & getenv(3)).
On Linux look also into proc(5) to understand what it is able to show about processes - thru /proc/1234/
for the process of pid 1234. Maybe you want seccomp facilities.
On Unix, be aware of the setuid mechanism -tricky to understand-. Use it carefully (it is the basic block of most security or authentication machinery such as sudo
and login
) since a simple mistake could open a huge vulnerability.
For a software written to work both on Unix & Windows, I recommend passing the password in some file (e.g. in /tmp/secretpassword
) and giving the name/tmp/secretpassword
(or some D:\foo\bar
on Windows) of that file thru some program argument, and make sure to use wisely the file permission mechanisms to ensure that file is not readable by those who don't need it.
Related Topics
I Can't Execute Command Modprobe Vboxdrv
Shell Script to Copy and Prepend Folder Name to Files from Multiple Subdirectories
What Does "$1/*" Mean in "For File in $1/*"
How to Update Cudnn to a Newer Version
Get a Nanosecond-Precise Atime, Mtime, Ctime Fields for File (Stat)
How to Know Which Device Is Connected in Which /Dev/Ttyusb Port
Command to Insert Lines Before First Match
How to Keep Executable Code in Memory Even Under Memory Pressure? in Linux
How to Recursively Search for Files with Certain Extensions
How to Set Cap_Sys_Nice Capability to a Linux User
How to Add a String to the Beginning of Each File in a Folder in Bash
Linux Mail < File.Log Has Content-Type: Application/Octet-Stream (A Noname Attachment in Gmail)
Find Command in Bash Script Resulting in "No Such File or Directory" Error Only for Directories
Convert Animated Gif to Video on Linux Server While Preserving Frame Rate