cymon has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I'm writing a CGI program that connects to a MySQL database using DBI. I would like to remove the username and password from the source of the script itself and--ideally--store it somewhere that can't be seen by others, save perhaps the machine's administrators.

(For the record, I did use search and super-search pretty carefully. While there are a lot of nodes on the system, I didn't see precisely the answer I was looking for. I'll admit, however, that I was overwhelmed by the number of hits and may have missed something while trying to scan them quickly.)

To begin, consider the following code (which is nothing special):

#!/usr/bin/perl -w use strict; use DBI(); my $dbh = DBI->connect( "DBI:mysql:database=mydb;host=localhost", "mywebuser", "mypassword", { 'RaiseError' => 1 } ); my $sth = $dbh->prepare( "SELECT * from mytable;" ); $sth->execute(); while ( my $ref = $sth->fetchrow_hashref() ) { print "Found a row: id = $ref->{ 'id' }, name = $ref->{ 'name' }\n"; } $sth->finish(); $dbh->disconnect;

That said, here's my question: How do I protect the password, as well as (preferably) the user name used to access the database?

I have considered encrypting the password, perhaps with an MD5 hash, but I'm not sure how to handle the decryption process without compromising the password. I am not asking for ways to obscure the password, but to truly protect it from prying eyes. (If this is a good idea, I could also use some pointers that might help avoid common mistakes.)

Thanks in advance for any help...

Replies are listed 'Best First'.
Re: Handling Passwords Securely
by Abigail-II (Bishop) on Feb 23, 2004 at 21:22 UTC
    MD5 hashes are one-way, so you can't "decrypt" a password of which you only have the MD5 hash. Unless you do a brute force attack, and have a lot of patience (or luck).

    Furthermore, encryption/decryption doesn't help. It doesn't help at all. If it's all "self-contained" (that is, there's no interaction with a source providing the password), the password will be visible for the EUID that runs the program. No matter how many times you encrypt. Because if you encrypt, you need to decrypt, and the steps to decrypt will be in the source. You've just transferred the need to keep the password a secret, to the need to keep the decryption key a secret....

    There may be ways to make things more secure, but then you first have to determine who you are defending against. The casual shoulder surfer? Other, normal, users on the system? People with access to the network? Hackers/crackers? Professional industrial spionage? The FBI/CIA/NSA/MI5/MI6/Mossad/KGB?

    Abigail

Re: Handling Passwords Securely
by cees (Curate) on Feb 23, 2004 at 21:32 UTC

    The only way to protect the password is to not store it on the system at all, and require it to be typed in everytime it is needed. There is no mechanism to secure the password from everybody and still allow your script to access it in a way that allows it to authenticate against another system (your database in this case). The closest you can get is to restrict it to only be readable to any users that have permission to run the script that needs the password.

    Now, that having been said, there are a couple of things you can do to make it easier to protect your passwords. Moving them out of the script itself is the first step. secondly, you need to place the strictest permissions possible on the file that does contain the password (remember that your script will need to be able to read it, so it needs to still be accessible by the user that your scripts are executed by - usually the same as what the webserver runs as).

    Since you are using MySQL, I would recommend using a MySQL config file to hold the password for you and then provide that config file in the DSN you pass to DBI. Here is some psuedocode to illustrate this technique:

    $dsn = "DBI:mysql:test;mysql_read_default_file=/var/lib/mysql/my.cnf"; $dbh = DBI->connect($dsn);
    Then in the my.cnf file you can place the following:
    [client] user="username" password="my_password"

    Make sure to remember to chown and chmod this file so that it is secure from 'most' prying eyes...

    - Cees

Re: Handling Passwords Securely
by saintmike (Vicar) on Feb 23, 2004 at 21:23 UTC
    Encrypting the username and password only helps if you're interactively typing in a passphrase to decrypt it at runtime.

    Otherwise, whatever your program does can be done by an attacker -- that's like securing a door with a $500 lock and placing the key under the doormat :).

Re: Handling Passwords Securely
by waswas-fng (Curate) on Feb 23, 2004 at 21:27 UTC
    One thing you can do, although it does not offer much more security, is place the user/pass in a file outside of the directory tree that is exposed by the web server. If they break into the web server they can still access the user and pass from that file (it has to be readable by the httpd/cgi user), but it is a little more secure (depending on your configuration) than being directly stored in the cgi.


    -Waswas
Re: Handling Passwords Securely
by mutated (Monk) on Feb 23, 2004 at 22:45 UTC
    Storing your password outside of your html root is a good start. Remember to configure your dbserver to only accept connections with that username/password from the webservers IP as well, it's not perfect protection, but at least an attacker somehow getting the username/password combo would need to attack the database server from that host. Also remember to give the account as few permissions as possible on the DB. Don't give the user delete or alter permissions on any table not absolutly neccesary, and definately don't give it drop or create permissions.
    daN.
Re: Handling Passwords Securely
by freddo411 (Chaplain) on Feb 24, 2004 at 00:53 UTC
    The above responses are correct. I'd like to add one rather expensive and unlikely option that could enhance security.

    The large unnamed bank that I work for uses a hardware encryption device installed in a PCI card on the system. These devices securely hold onto the decrypting key information in protected memory, and provide decryption services via an api. Under no circustances (assuming their engineering is not flawed) do these devices devulge the keys stored in them, they can only be reloaded with different keys. Key loading is generally done offline, on another machine not connected to the net.

    While this system actually solves the issues (net attacks) you raised in your post, it can still be defeated by persons that are responsible for loading and handling the keys (inside job).

    Cheers

    --Fred

    -------------------------------------
    Nothing is too wonderful to be true
    -- Michael Faraday