http://qs1969.pair.com?node_id=1183367


in reply to Re: How can a script use a password without making the password visible?
in thread How can a script use a password without making the password visible?

Passwords, hashes, and salt

Crypt::Password

Storing Password in an easy and secure way using Perl

I didn't bother to read the article at the third link in detail, the headings are sufficient to know that this does not answer the question. This nice article hashes passwords and adds salting. An excellent idea when working with user passwords (see Anger Management). But it absolutely does not help when your script needs to present a password to an external service, like a database. The point of hashing and salting is to make the password unrecoverable, or at least make it hard to recover it (see Rainbow Tables).

Data::Encrypted

This actually allows to store and recover data in an encrypted way. But this module is severely limited on its own:

SSH1 vs. SSH2 and other public-key considerations

Data::Encrypted utilizes the facilities made available by Crypt::RSA, and so is limited only by Crypt::RSA's ability to read and utilize various public key formats. Currently that means that only SSH version 1 keys are usable. Furthermore, keys which have been themselves encrypted via use of a 'passphrase' are currently unusable by Data::Encrypted -- future versions may overcome this limitation.

Yes, it does encrypt any data you wish, like a database username and password. But: It relies on two files on the same machine (the private and public RSA key files), it uses old crypto algorithms (RSA, SSH1), and it can't even handle private keys with passphrases.

What does that gain? An attacker needs to copy not only the encrypted configuration file, but also the private key file (~/.ssh/id_rsa.pub). The public key can easily be derived from the private key file. And as Data::Encrypted does not support private keys that need a passphrase, the attacker does not have to guess anything. Having the private key file is sufficient to decrypt the configuration file. So, instead of copying one file with mode 0600, the attacker has to copy two files with mode 0600. That's a 100% security improvement. Bonus points for spotting any irony in the previous sentence.

Now, how much work is required to decrypt the configuration file? Let's assume the attacker was able not only to copy the private key file and the encrypted configuration file, but also the script. And let's assume the script followed the "Real Life Examples" from Data::Encrypted. Then the script will contain something like this:

use DBI; use Data::Encrypted; my $encryptor = Data::Encrypted->new(FILE => 'db.conf'); my $dbh = DBI->connect( 'dbi:mysql:mydatabase', $encryptor->encrypted('user name'), $encryptor->encrypted('db password'), { RaiseError => 1, AutoCommit => 1} );

Let's modify that, just a little bit:

use DBI; use Data::Encrypted; my $encryptor = Data::Encrypted->new(FILE => 'db.conf'); my $dbh = die join(' :: ', # <--- this is the only line modified 'dbi:mysql:mydatabase', $encryptor->encrypted('user name'), $encryptor->encrypted('db password'), { RaiseError => 1, AutoCommit => 1} );

And then run it:

dbi:mysql:mydatabase :: clueless :: t0ps3cr3t :: HASH(0x1158f30) at pe +rfectlysecure.pl line 10.

Did you notice how much I had to think about crypto for that attack? Exactly zero. I didn't break RSA at all.

Now, let's imagine what would happen if Data::Encrypted would actually use current crypto algorithms, the hardest ones you could imagine, and it would support using a passphrase to unlock the private key. What would that gain?

Better crypto does not help at all, because the data is available in clear in the script. Replacing DBI->connect(...) with die join(' :: ',...) is successful even with the best crypto available on the planet.

Using a passphrase would annoy the user, because (s)he had to type in the passphrase every time (s)he wants to use the script. That won't work at all in a server context, by the way. So, what does a lazy user do? Exactly, remove that annoying passphrase or change it to something trivial like 12345, qwerty, or asdf. But the user does not have to enter the database password.

So, is the DB password well-protected? Nope, nothing stops the user from running a modified script that reveals database user and database password. I've shown above how easy that is.

Related: Re^2: Where should I have configuration information in a file or database, Re^2: best way to store login information for a perl script?, Re: Protection for Perl Scripts, Re^3: Code hiding in Perl

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)