Differences between revisions 10 and 16 (spanning 6 versions)
Revision 10 as of 2011-11-08 14:23:33
Size: 2982
Editor: pgas
Comment: fix link add empty
Revision 16 as of 2019-03-19 13:26:27
Size: 5423
Editor: GreyCat
Comment: Generalize to more than ssh, clean up, rewrite.
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
'''STOP!''' When dealing with authentication in a shell script, please bear in mind the following points:
Line 5: Line 5:
First of all, if you actually were to embed your password in a script somewhere, it would be visible to the entire world (or at least, anyone who can read files on your system). This would defeat the entire purpose of having a password on your remote account.  1. Do not pass secrets (passwords, etc.) as arguments to external commands. The arguments of a command are generally visible in `ps(1)` output. (See Linux-specific notes below, but not everyone is using a Linux system to which they have administrative access.)
 1. Do not pass secrets as environment variables. The initial environment of a process is generally visible in `ps(1)` (see below).
 1. Read the documentation of the thing you're trying to authenticate against. Find out the various ways it can accept authentication secrets/tokens and choose the most appropriate. This may mean using SSH public key authentication as described below, or connecting to a database via a Unix-domain socket instead of a TCP connection to `localhost`, etc.
 1. If something requires a password, let it prompt the user for the password by itself. Just run it in the foreground inside a terminal so that it can launch a dialog with the end user if required. Do not try to "help" it by storing the password in your script and then trying to figure out how to circumvent its security in order to pass the password to it.
 1. If you absolutely ''must'' store a password somewhere on disk, don't store it inside the shell script. Shell scripts must have read permissions in order to be used. Store the password in a separate file that doesn't have universal read permission, and let the appropriate process read that file. The appropriate process may be your script in rare cases, but more often it'll be whatever program is actually going to use that password.
Line 7: Line 11:
If all you want is for the user to be prompted for a password by `ssh`, simply make sure your script is executed in a terminal and that your `ssh` command is executed in the foreground ("normally"). `ssh` will prompt the user for a password if the remote server requires one for authentication.  Your script doesn't need to get involved. If all you want is for the user to be prompted for a password by `ssh`, simply make sure your script is executed in a terminal and that your `ssh` command is executed in the foreground ("normally"). Either `ssh` or the program specified in the `SSH_ASKPASS` environment variable will prompt the user for a password if the remote server requires one for authentication.
Line 9: Line 13:
Specifically, '''do not''' ask the user for their password yourself, store it in a variable, and then try to pass it along to `ssh`. That reduces your security enormously. If you want to bypass SSH password authentication entirely, then you should use ''public key authentication'' instead. Read and understand the man page for `ssh-keygen(1)`, or see SshKeys for a brief overview. This will tell you how to generate a public/private key pair, and how to use these keys to authenticate to the remote system without sending a password at all.
Line 11: Line 15:
If you want to bypass the password authentication entirely, then you should use ''public key authentication'' instead. Read and understand the man page for `ssh-keygen(1)`, or see SshKeys for a brief overview. This will tell you how to generate a public/private key pair (in either RSA or DSA format), and how to use these keys to authenticate to the remote system without sending a password at all.

Here is a brief summary of the procedure:
Here is a brief summary of the key generation procedure:
Line 16: Line 18:
ssh-keygen -t rsa
ssh me@remote "cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_rsa.pub
ssh me@remote date     # should not prompt for a passWORD,
test -f ~/.ssh/id_rsa || ssh-keygen -t rsa
ssh-copy-id me@remote
ssh me@remote hostname # should not prompt for a passWORD,
Line 22: Line 24:
If your key has a passphrase on it, and you want to avoid typing it every time, look into {{{ssh-agent(1)}}}. It's beyond the scope of this document, though. If your script has to run unattended, then you may need to remove the passphrase from the key. This reduces your security, because then anyone who grabs the key can log in to the remote server as you (it's equivalent to putting a password in a file). However, sometimes this is deemed an acceptable risk. If your key has a passphrase on it, and you want to avoid typing it every time, look into `ssh-agent(1)`. It's beyond the scope of this document, though. If your script has to run unattended, then you may need to remove the passphrase from the key. This reduces your security, because then anyone who grabs the key can log in to the remote server as you (it's equivalent to putting a password in a file). However, sometimes this is deemed an acceptable risk.
Line 24: Line 26:
If you're being prompted for a password even with the public key inserted into the remote {{{authorized_keys}}} file, chances are you have a permissions problem on the remote system. See SshKeys for a discussion of such problems. If you're being prompted for a password even with the public key inserted into the remote `authorized_keys` file, chances are you have a permissions problem on the remote system. See SshKeys for a discussion of such problems.
Line 28: Line 30:
If you ''really'' want to store a password in a variable and then pass it to a program, instead of using public keys, first have your head examined. Then, if you ''still'' want to use a password, use [[http://expect.sf.net/|expect(1)]] (or the less classic but maybe more bash friendly [[http://empty.sf.net|empty(1)]]). But don't ask us for help with it. If you ''really'' want to store a password in a variable and then pass it to SSH, instead of using public keys, first have your head examined. Then, if you ''still'' want to use a password, use [[http://expect.sf.net/|expect(1)]] (or the less classic but maybe more bash friendly [[http://empty.sf.net|empty(1)]]). But don't ask us for help with it.
Line 31: Line 33:

=== Limiting access to process information ===

Information about processes is often visible to every user on the system via the `ps(1)` command or via pseudo-files in the `/proc` file system (which is where `ps` reads its information on Linux and certain other operating systems). Specifically, the '''arguments''' of a process are generally visible to all users on all Unix-based systems, and the '''initial environment''' of a process is generally visible to all users on traditional BSD-based systems (including older Linux systems).

The implementation details are specific to each operating system. For Linux, consult `proc(5)` (here's one version [[https://manpages.debian.org/stretch/manpages/proc.5.en.html|from Debian 9]], circa 2016).

If you're the administrator of a system, you may be able to change security settings in order to prevent password leaks by the worst sorts of programs that accept passwords as command-line arguments (''cough'' mysql).

However, most people writing a shell script do not have the luxury of assuming that a system has been hardened beyond the default settings. We must write for the most common cases. This means following the standard advice given at the top of this page whenever possible.

I want to automate an ssh (or scp, or sftp) connection, but I don't know how to send the password....

When dealing with authentication in a shell script, please bear in mind the following points:

  1. Do not pass secrets (passwords, etc.) as arguments to external commands. The arguments of a command are generally visible in ps(1) output. (See Linux-specific notes below, but not everyone is using a Linux system to which they have administrative access.)

  2. Do not pass secrets as environment variables. The initial environment of a process is generally visible in ps(1) (see below).

  3. Read the documentation of the thing you're trying to authenticate against. Find out the various ways it can accept authentication secrets/tokens and choose the most appropriate. This may mean using SSH public key authentication as described below, or connecting to a database via a Unix-domain socket instead of a TCP connection to localhost, etc.

  4. If something requires a password, let it prompt the user for the password by itself. Just run it in the foreground inside a terminal so that it can launch a dialog with the end user if required. Do not try to "help" it by storing the password in your script and then trying to figure out how to circumvent its security in order to pass the password to it.
  5. If you absolutely must store a password somewhere on disk, don't store it inside the shell script. Shell scripts must have read permissions in order to be used. Store the password in a separate file that doesn't have universal read permission, and let the appropriate process read that file. The appropriate process may be your script in rare cases, but more often it'll be whatever program is actually going to use that password.

If all you want is for the user to be prompted for a password by ssh, simply make sure your script is executed in a terminal and that your ssh command is executed in the foreground ("normally"). Either ssh or the program specified in the SSH_ASKPASS environment variable will prompt the user for a password if the remote server requires one for authentication.

If you want to bypass SSH password authentication entirely, then you should use public key authentication instead. Read and understand the man page for ssh-keygen(1), or see SshKeys for a brief overview. This will tell you how to generate a public/private key pair, and how to use these keys to authenticate to the remote system without sending a password at all.

Here is a brief summary of the key generation procedure:

test -f ~/.ssh/id_rsa || ssh-keygen -t rsa
ssh-copy-id me@remote
ssh me@remote hostname # should not prompt for a passWORD,
                       # but your key may have a passPHRASE

If your key has a passphrase on it, and you want to avoid typing it every time, look into ssh-agent(1). It's beyond the scope of this document, though. If your script has to run unattended, then you may need to remove the passphrase from the key. This reduces your security, because then anyone who grabs the key can log in to the remote server as you (it's equivalent to putting a password in a file). However, sometimes this is deemed an acceptable risk.

If you're being prompted for a password even with the public key inserted into the remote authorized_keys file, chances are you have a permissions problem on the remote system. See SshKeys for a discussion of such problems.

If that's not it, then make sure you didn't spell it authorised_keys. SSH uses the US spelling, authorized_keys.

If you really want to store a password in a variable and then pass it to SSH, instead of using public keys, first have your head examined. Then, if you still want to use a password, use expect(1) (or the less classic but maybe more bash friendly empty(1)). But don't ask us for help with it.

expect also applies to the telnet or FTP variations of this question. However, anyone who's still running telnetd without a damned good reason needs to be fired and replaced.

Limiting access to process information

Information about processes is often visible to every user on the system via the ps(1) command or via pseudo-files in the /proc file system (which is where ps reads its information on Linux and certain other operating systems). Specifically, the arguments of a process are generally visible to all users on all Unix-based systems, and the initial environment of a process is generally visible to all users on traditional BSD-based systems (including older Linux systems).

The implementation details are specific to each operating system. For Linux, consult proc(5) (here's one version from Debian 9, circa 2016).

If you're the administrator of a system, you may be able to change security settings in order to prevent password leaks by the worst sorts of programs that accept passwords as command-line arguments (cough mysql).

However, most people writing a shell script do not have the luxury of assuming that a system has been hardened beyond the default settings. We must write for the most common cases. This means following the standard advice given at the top of this page whenever possible.

BashFAQ/069 (last edited 2019-04-11 12:53:15 by GreyCat)