18

How can I hide a password in shell scripts? There are a number of scripts that are accessing database. If we open the script others also aware the username and password. So if anyone knows how to hide please let me know.

I have one way: place the password in a file and make the file as hidden and no one going to access the file (change the permissions and use the file in script while going to accessing database).

31

First, as several people have already said, keeping the credentials separate from the script is essential. (In addition to increased security, it also means that you can re-use the same script for several systems with different credentials.)

Second, you should consider not only the security of the credentials, but also the impact if/when those credentials are compromised. You shouldn't have just one password for all access to the database, you should have different credentials with different levels of access. You could, for instance, have one DB user that has the ability to perform a search in the database - that user should have read-only access. Another user may have permission to insert new records, but not to delete them. A third one may have permission to delete records.

In addition to restricting the permissions for each account, you should also have restriction on where each account can be used from. For instance, the account used by your web server should not be allowed to connect from any other IP address than that of the web server. An account with full root permissions to the database should be very restricted indeed in terms of where it may connect from and should never be used other than interactively. Also consider using stored procedures in the database to restrict exactly what can be done by each account.

These restrictions need to be implemented on the DB-server side of the system, so that even if the client side is compromised, the restrictions cannot be altered from it. (And, obviously, the DB server needs to be protected with firewalls etc in addition to the DB configuration...)

In the case of a DB account that is only permitted limited read-only access, and only from a particular IP address, you might not need any further credentials than that, depending on the sensitivity of the data and the security of the host the script is being run from. One example may be a search form on your web site, which can be run with a user that is only allowed to use a stored procedure which extracts only the information that will be presented on the web page. In this case, adding a password does not really confer any extra security, since that information is already meant to be public, and the user can't access any other data that would be more sensitive.

Also make sure that the connection to the database are made using TLS, or anybody listening on the network can get your credentials.

Third, consider what kind of credentials to use. Passwords are just one form, and not the most secure. You could instead use some form of public/private key pair, or AD/PAM or the like.

Fourth, consider the conditions under which the script will be run:

If it is run interactively, then you should enter the password, or the password to the private key, or the private key, or be logged in with a valid Kerberos ticket, when you run it - in other words, the script should get its credentials directly from you at the time that you run it, instead of reading them from some file.

If it is run from a webserver, consider setting up the credentials at the time when you start the webserver. A good example here is SSL certificates - they have a public certificate and a private key, and the private key has a password. You may store the private key on the webserver, but you still need to enter the password to it when you start Apache. You could also have the credentials on some kind of hardware, such as a physical card or an HSM, that can be removed or locked once the server is started. (Of course, the downside to this method is that the server can't restart on its own if something happens. I would prefer this to the risk of having my system compromised, but your mileage may vary...)

If the script is being run from cron, this is the hard part. You don't want to have the credentials lying around anywhere on your system where someone can access them - but you do want to have them lying around so that your script can access them, right? Well, not quite right. Consider exactly what the script is doing. What permissions does it need on the database? Can it be restricted so that it doesn't matter if the wrong person connects with those permissions? Can you instead run the script directly on the DB server that nobody else has access to, instead of from the server that does have other users? If, for some reason that I can't think of, you absolutely must have the script running on an insecure server and it must be able to do something dangerous/destructive... now is a good time to re-think your architecture.

Fifth, if you value the security of your database, you should not be running these scripts on servers that other people have access to. If someone is logged in on your system, then they will have the possibility to get at your credentials. For instance, in the case of a webserver with an SSL certificate, there is at least a theoretical possibility of someone being able to gain root and access the httpd process's memory area and extract the credentials. There has been at least one exploit in recent times where this could be done over SSL, not even requiring the attacker to be logged in.

Also consider using SELinux or apparmor or whatever is available for your system to restrict which users can do what. They will make it possible for you to disallow users to even try to connect to the database, even if they do manage to gain access to the credentials.

If all this sounds like overkill to you, and you can't afford or don't have the time to do it - then, in my (arrogant and elitist) opinion, you should not be storing anything important or sensitive in your database. And if you're not storing anything important or sensitive, then where you store your credentials is also not important - in which case, why use a password at all?

Lastly, if you absolutely cannot avoid storing some kind of credentials, you could have the credentials read-only and owned by root and root could grant ownership on an exceedingly temporary basis when requested to do so by a script (because your script should not be run as root unless absolutely necessary, and connecting to a database does not make it necessary). But it's still not a good idea.

  • 7
    Not arrogant and elitist at all. Or else I am, too. "How can I protect my jewelry in case a burglar breaks in?" "Put it in a safe that is bolted/welded in place." "That's too much trouble, I'll just get a portable safe and hang the key from a hook." "Then don't bother using a safe." Eminently sensible advice. – Wildcard May 6 '16 at 18:32
9

First of all, if there is any way at all you can change things to avoid having to store a password inside or alongside a script in the first place, you should make every effort to do that. Jenny D's answer contains a lot of good advice to that effect.

Otherwise, your idea of placing the password in a separate file with restricted permissions is pretty much it. You can for example source that file from the main script:

. /usr/local/etc/secret-password-here

You could also restrict the permissions of the main script so that only authorized persons can execute it, but it's probably better to do as you suggest and store only the password itself in a restricted file. That way you can allow inspection of the code itself (without sensitive secrets), version-control and copy around the script more easily, etc...

  • 1
    So, I was wrong and I delete my comments. – Basile Starynkevitch Jun 26 '15 at 6:51
  • @BasileStarynkevitch ah but I see that it also says "/usr/local/etc may be a symbolic link to /etc/local". I missed that. So you're also right, but it's a MAY so it's optional. But yeah, it doesn't matter much, and personal preference. – Celada Jun 26 '15 at 6:53
  • Except that I am backuping /etc/ but not /usr/local/ (which I assume can be rebuilt after disk crash) – Basile Starynkevitch Jun 26 '15 at 6:54
  • fair point about backups – Celada Jun 26 '15 at 6:55
2

Other answers have addressed the how, but I'll consider the whether. Depending on what kind of database your users are connecting to, you might already have a suitable mechanism that's already used by those client programs, in which case be sure to use them (I'm thinking of ~/.mysqlrc or ~/.pgpass).

If you're giving several users the ability to access the database to make specific queries using a shared account, then you probably shouldn't. Instead, make sure they have accounts on the database and that those accounts have no more permissions than they need (probably read on much of it, and very little write access). If they need to make specific queries on certain tables that they can't otherwise access, provide stored procedures with SECURTY DEFINER to allow them to do so.

If none of the above avoids you needing to store credentials, then read the other answers here.

1

Your idea of hiding the password in an inaccessible place might be OK depending on the circumstances.

If the information is separate, that means simple editing of the file, e.g. during a code review with a colleague is not going to show it. But realise anyone with access to your account can easily find such a file. I have used a subdirectory of ~/.ssh for such purposes, for the simple reason that ssh complains if the access rights for ~/.ssh are not restricted enough.

There are however other things you can do to prevent such glancing of username and/or passwords.

Obfuscating: If you don't want anyone to read the username or password while you edit a script you can put it in the text but not as plain text, but obfuscated. If the obfuscated version is long enough preventing its memorization by someone looking at it, it cannot be known even if the decryption method and key are in plain sight. This would of course still be trivially circumvented by someone having access to your account.

Using GPG:

Slightly better, but still not full proof against attacks by the root user on your system, is to encrypt username/password pairs in a file your gpg public and having the script retrieve the content on the file (possible prompting you for a password, if not cached/expired). I use ggp-card so that when I leave my laptop around but pull the card out, no access is possible even if the pin would still be cached. At least if I run thing 20 times in a few minutes I have to provide the pin only once.

Security seems always inversely related to convenience (setting up and using).

0

There's a way to store passwords in a bash script but you have to encrypt and obfuscate the script so that no one can actually read it or run any type of debugger on it to see exactly what it is doing. To encrypt and obfuscate a bash/shell script and have it actually be executable, try copying and pasting it here:

http://www.kinglazy.com/shell-script-encryption-kinglazy-shieldx.htm

On the above page, all you have to do is submit your script (you can submit a sample script first for your peace of mind). A zip file will be generated for you. Right click on the download link and copy the URL you're provided. Then, go to your UNIX box and perform the following steps.

Installation:

  1. wget link-to-the-zip-file

  2. unzip the-newly-downloaded-zip-file

  3. cd /tmp/KingLazySHIELD

  4. ./install.sh /var/tmp/KINGLAZY/SHIELDX-(your-script-name) /home/(your-username) -force

What the above install command will do for you is:

  1. It'll install the encrypted version of your script in the directory /var/tmp/KINGLAZY/SHIELDX-(your-script-name).

  2. It'll place a link to this encrypted script in whichever directory you specify in replacement of /home/(your-username) - that way, it allows you to easily access the script without having to type the absolute path.

  3. Ensures NO ONE can modify the script - Any attempts to modify the encrypted script will render it inoperable...until those attempts are stopped or removed. It can even be configured to notify you whenever someone tries to do anything with the script other than run it...i.e. hacking or modification attempts.

  4. Ensures absolutely NO ONE can make copies of it. No one can copy your script to a secluded location and try to screw around with it to see how it works. All copies of the script must be links to the original location which you specified during install (step 4).

NOTE:

I don't believe this works for interactive scripts that prompts the user for a response. The values should be hard-coded into the script. The encryption ensures no one can actually see those values so you need not worry about that.

0

Another solution, without regard to security (I also think it is better to keep the credentials in another file or in a database) is to encrypt the password with gpg and insert it in the script.

I use a password-less gpg key pair that I keep in a usb. (Note: When you export this key pair don't use --armor, export them in binary format).

First encrypt your password:

echo -n "pAssw0rd" | gpg --armor --no-default-keyring --keyring /media/usb/key.pub --recipient someone@mail.com --encrypt

That will be print out the gpg encrypted password in the standart output. Copy the whole message and add this to the script:

password=$(gpg --batch --quiet --no-default-keyring --secret-keyring /media/usb/key.priv --decrypt <<EOF 
-----BEGIN PGP MESSAGE-----

hQEMA0CjbyauRLJ8AQgAkZT5gK8TrdH6cZEy+Ufl0PObGZJ1YEbshacZb88RlRB9
h2z+s/Bso5HQxNd5tzkwulvhmoGu6K6hpMXM3mbYl07jHF4qr+oWijDkdjHBVcn5
0mkpYO1riUf0HXIYnvCZq/4k/ajGZRm8EdDy2JIWuwiidQ18irp07UUNO+AB9mq8
5VXUjUN3tLTexg4sLZDKFYGRi4fyVrYKGsi0i5AEHKwn5SmTb3f1pa5yXbv68eYE
lCVfy51rBbG87UTycZ3gFQjf1UkNVbp0WV+RPEM9JR7dgR+9I8bKCuKLFLnGaqvc
beA3A6eMpzXQqsAg6GGo3PW6fMHqe1ZCvidi6e4a/dJDAbHq0XWp93qcwygnWeQW
Ozr1hr5mCa+QkUSymxiUrRncRhyqSP0ok5j4rjwSJu9vmHTEUapiyQMQaEIF2e2S
/NIWGg==
=uriR
-----END PGP MESSAGE-----
EOF)

In this way only if the usb is mounted in the system the password can be decrypted. Of course you can also import the keys into the system (less secure, or no security at all) or you can protect the private key with password (so it can not be automated).

-2
#!/bin/bash
unset username
unset password
unset dbname
echo -n "username:"
read username
echo -n "dbname:"
read dbname
prompt="password:"

    while IFS= read -p "$prompt" -r -s -n 1 char
            do
                    if [[ $char == $'\0' ]]
                            then
                                    break
                    fi
                    prompt='*'
                    password+="$char"
            #       read -s -p "Enter Password: "  pswd
            #       echo -e "\nYour password is: " $pswd
            done
  • 2
    I indented your code, maybe you could explain what you are trying to do ? – Archemar Jun 26 '15 at 13:13
-5

I don't believe you should ever store the password. I can't think of a single good reason for that. Rather, you should store a salted hash of that password - some string which is produced reliably by some function when the original password is passed as input, but never the password.

  • 4
    I'm unclear on how this will solve the problem of a) being able to connect to a service requiring a password, and b) users being able to see the script and thus being able to figure out the authentication details, whether those are passwords or not – Jenny D Jun 26 '15 at 7:28
  • 1
    You are claiming to know my answer before I've written it. – Jenny D Jun 26 '15 at 8:27
  • 1
    I've written my answer now. What I was trying to get at from you was partly my fifth point - once the credentials are stored in memory they are not fully secure from an attacker with access to the server. Also that your terse answer was not very helpful, even though not incorrect. I'm thinking of pointing at it the next time someone complains that we at ServerFault are not as nice as the people at Unix/Linux :-) – Jenny D Jun 26 '15 at 9:50
  • 2
    @JennyD - once the cred is in memory - it certainly doesn't need to stay there - and that's a very good reason to deal w/ hashes instead anyway. Still, i'll happily represent community's courtesy standards as its exemplar at large - im very well known for that trait, in fact. – mikeserv Jun 26 '15 at 9:57
  • 3
    After your big discussion I would just like to mention in case there's any misunderstanding that it was I who downvoted, not Jenny. And the reason wasn't an opinion on whether or not it's a good idea to use a certificate&privkey or interactively-entered password or do what the OP wanted or whatever. It was because the answer as it stands is wrong: storing a salted hash of the password as a client credential isn't a thing: salted hashes are a thing you keep on the end of the connection that is verifying the auth, not on the side that is submitting it. – Celada Jun 26 '15 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.