Protecting passwords in Perl scripts?

D

David Filmer

I have (for example) a Perl script that connects to a database (or FTP site,
etc). The database (or ftp) password is either hard-coded (in clear text) in
the script or contained in an external configuration file (which must be
readable by the effective uid of the script).

Someone who was able to browse the code could easily determine the password.
That's a Bad Thing.

I could trivially obfuscate it (rot13, etc) but that would only thwart the
truly ignorant. The password could be symmetrically encrypted, but the
script somehow needs to determine the encryption key (and the idly curious
could determine this as well by reading the code).

How can I shield the database (ftp, etc) password from prying eyes?
 
B

Brian McCauley

David said:
I have (for example) a Perl script that connects to a database (or FTP site,
etc). The database (or ftp) password is either hard-coded (in clear text) in
the script or contained in an external configuration file (which must be
readable by the effective uid of the script).

Someone who was able to browse the code could easily determine the password.
That's a Bad Thing.

I could trivially obfuscate it (rot13, etc) but that would only thwart the
truly ignorant. The password could be symmetrically encrypted, but the
script somehow needs to determine the encryption key (and the idly curious
could determine this as well by reading the code).

How can I shield the database (ftp, etc) password from prying eyes?

You cannot. You are looking for a perpetual motion machine. It is
impossible to write a program fragment that generates prescribed secret
output (e.g. a password) but which a programmer given the program and
the environment in which it is run cannot find out what secret is.
This has nothing to do with Perl.
 
A

Andrew Bryson

David Filmer said:
I have (for example) a Perl script that connects to a database (or FTP
site, etc). The database (or ftp) password is either hard-coded (in clear
text) in the script or contained in an external configuration file (which
must be readable by the effective uid of the script).

Someone who was able to browse the code could easily determine the
password. That's a Bad Thing.

I could trivially obfuscate it (rot13, etc) but that would only thwart the
truly ignorant. The password could be symmetrically encrypted, but the
script somehow needs to determine the encryption key (and the idly curious
could determine this as well by reading the code).

How can I shield the database (ftp, etc) password from prying eyes?

I do not believe that you can although that said I know little about
encryption and I suppose it might be possible to construct a non-reversible
operation that was still useful.

However you can take steps to minimise the risk. For one thing, do not store
the file containing the password in a directory that is accessible from
anywhere other than the local machine. That way at least someone has to be
able to log in to your machine before they can read it, and if they can
manage to log in there is a good chance that they can break in to your
database as well :). Also, make sure that the file containing the password
is only readable by the user running the perl script. I am sure that there
are other things you can do too. Undoubtedly someone will mention them.

Andrew Bryson
http://www.bryson.co.nz
 
S

Sherm Pendley

Andrew said:
However you can take steps to minimise the risk. For one thing, do not store
the file containing the password in a directory that is accessible from
anywhere other than the local machine. That way at least someone has to be
able to log in to your machine before they can read it, and if they can
manage to log in there is a good chance that they can break in to your
database as well :). Also, make sure that the file containing the password
is only readable by the user running the perl script. I am sure that there
are other things you can do too. Undoubtedly someone will mention them.

Okay, here's more:

Have the script log in with a database user that has *only* the
privileges that the script needs to do its job, and nothing more. For
example, if the script simply generates a report, give it read access,
but not write or admin access.

sherm--
 
M

Michele Dondi

You cannot. You are looking for a perpetual motion machine. It is
impossible to write a program fragment that generates prescribed secret
output (e.g. a password) but which a programmer given the program and
the environment in which it is run cannot find out what secret is.
This has nothing to do with Perl.

<OT>
True. But I think the OP may find interesting the article "Password
Authentication with Insecure Communication", by Leslie Lamport. I
haven't read it myself, but I saw a description of the algorithm in
Tanenbaum's "Modern Operating Systems".
</OT>


Michele
 
E

Eric Schwartz

David Filmer ([email protected]) wrote:
: How can I shield the database (ftp, etc) password from prying eyes?

Put the config data in a file that belongs to another user, and chmod so
it cannot be read by anyone else.

If this is on Linux, you may (depending on your support requirements)
be able to take advantage of SELinux. With that, you can define a
security context in which your program will operate, and place the
config file in that context as well, and then even if the permissions
on the file are 777, nobody can read it who is not explicitly allowed.

-=Eric
 
M

Malcolm Dew-Jones

David Filmer ([email protected]) wrote:
: I have (for example) a Perl script that connects to a database (or FTP site,
: etc). The database (or ftp) password is either hard-coded (in clear text) in
: the script or contained in an external configuration file (which must be
: readable by the effective uid of the script).

: Someone who was able to browse the code could easily determine the password.
: That's a Bad Thing.

: I could trivially obfuscate it (rot13, etc) but that would only thwart the
: truly ignorant. The password could be symmetrically encrypted, but the
: script somehow needs to determine the encryption key (and the idly curious
: could determine this as well by reading the code).

: How can I shield the database (ftp, etc) password from prying eyes?

Put the config data in a file that belongs to another user, and chmod so
it cannot be read by anyone else.

Now make the script suid or guid so it can read the config file when it
runs.

I don't guarantee this is 100% effective. I'm not sure if it's possible
to hack the running perl script to dump the password after reading it.
 
D

David Filmer

But I think the OP may find interesting the article "Password
Authentication with Insecure Communication", by Leslie Lamport.

Dr. Lamport is a researcher with Micro$oft (but I won't hold that
against him - the guy is brilliant, so there is at least one really
smart guy working at Micro$oft). He kindly makes many of his writings
available to the public at
http://research.microsoft.com/users/lamport/pubs/pubs.html.

This paper is interesting, but it is confined to the problem of
password eavesdropping. I don't think the idea he proposes (using
one-time passwords in sequence) applies to this problem.

I agree with the opinions expressed here that the best we can do is to
try to lock down the environment. The problem cannot be solved within
the Perl code, and thus is not really a Perl issue.
 
M

Michele Dondi

Dr. Lamport is a researcher with Micro$oft (but I won't hold that
against him - the guy is brilliant, so there is at least one really
smart guy working at Micro$oft). He kindly makes many of his writings

He's also pioneered and thus made available to us LaTeX, although
AFAICT he's no more involved with it apart, possibly, for the rights
of the book ;-)

IIRC he was at DEC way back then.

Good to know.
This paper is interesting, but it is confined to the problem of
password eavesdropping. I don't think the idea he proposes (using
one-time passwords in sequence) applies to this problem.

I think so too. This is why I marked my cmt as OT. More precisely it
only *marginally* applies to this problem in that it allowes users to
log in securely over a net whose traffic can be seen by an intruder
*and* it doesn't require storing secret keys either on the client or
the server. The user still have to choose and memorize a "starting"
pw, so that indeed we're stuck back at the same point...


Michele
 
M

Mark Shelor

David said:
I have (for example) a Perl script that connects to a database (or FTP site,
etc). The database (or ftp) password is either hard-coded (in clear text) in
the script or contained in an external configuration file (which must be
readable by the effective uid of the script).

Someone who was able to browse the code could easily determine the password.
That's a Bad Thing.

I could trivially obfuscate it (rot13, etc) but that would only thwart the
truly ignorant. The password could be symmetrically encrypted, but the
script somehow needs to determine the encryption key (and the idly curious
could determine this as well by reading the code).

How can I shield the database (ftp, etc) password from prying eyes?


I've written and maintained many such scripts, so this is a topic of
personal interest. I believe I've finally settled on an "optimal"
approach, though individual tastes will certainly vary.

There are several possible techniques. Each has its own advantages and
disadvantages, depending on the threat(s) you envisage. But, under
normal circumstances, I'd simply recommend your second option: moving
the passwords to a configuration file, and reading them into the script
at runtime.

Don't bother with encryption or set-id's, at least not initially. They
make software a pain to use and modify, and are likely not appropriate
to the actual threats you face. By moving the passwords to a
configuration file, you solve 90% of the problem: namely, you can now
copy your scripts anywhere or share them with anyone, and cut-and-paste
from them freely without compromising your security.

However, if other users can browse your directories and read your files
at will, then you have a problem. Simply protect your configuration
files from access by others, and you've eliminated most of the
reasonable threats.

That said, if the threats are more dire, I'd recommend encrypting the
configuration files with GnuPG, and then decrypting/re-encrypting them
within your scripts via the --use-agent option. This necessitates
running gpg-agent as a daemon to automate the passphrase handling. Once
you get things set up, this approach is _very_ secure and fairly easy
to maintain. But it's probably overkill for what you're doing.

Or, you can rig up a quick-and-dirty "password safe" in Perl using a
hash tie'ed to a DB_File. There are many ways to obfuscate the contents
of the safe so that running "strings" on the db file won't reveal the
passwords. Still, unlike GnuPG, it won't foil the determined intruder.

Regards, Mark
 
B

Ben Morrow

Quoth (e-mail address removed) (Malcolm Dew-Jones):
David Filmer ([email protected]) wrote:
: I have (for example) a Perl script that connects to a database (or FTP site,
: etc). The database (or ftp) password is either hard-coded (in clear text) in
: the script or contained in an external configuration file (which must be
: readable by the effective uid of the script).

: Someone who was able to browse the code could easily determine the password.
: That's a Bad Thing.

: I could trivially obfuscate it (rot13, etc) but that would only thwart the
: truly ignorant. The password could be symmetrically encrypted, but the
: script somehow needs to determine the encryption key (and the idly curious
: could determine this as well by reading the code).

: How can I shield the database (ftp, etc) password from prying eyes?

Put the config data in a file that belongs to another user, and chmod so
it cannot be read by anyone else.

Now make the script suid or guid so it can read the config file when it
runs.

I don't guarantee this is 100% effective. I'm not sure if it's possible
to hack the running perl script to dump the password after reading it.

That's avoidable by not giving write permission to the script. IIRC most
Unix kernels will remove any setid bits if a non-owner writes to a
setid file, so an attacker wouldn't get anywhere anyway.

Ben
 
C

ctcgag

David Filmer said:
I have (for example) a Perl script that connects to a database (or FTP
site, etc). The database (or ftp) password is either hard-coded (in clear
text) in the script or contained in an external configuration file (which
must be readable by the effective uid of the script).

Someone who was able to browse the code could easily determine the
password. That's a Bad Thing.

So don't let them browse your code!
I could trivially obfuscate it (rot13, etc) but that would only thwart
the truly ignorant. The password could be symmetrically encrypted, but
the script somehow needs to determine the encryption key (and the idly
curious could determine this as well by reading the code).

So don't let them browse your code!
How can I shield the database (ftp, etc) password from prying eyes?

Shield it from prying eyes while still allowing......what?

other people to look at the code?
other people to meaningfully execute the code?
other people to look at and meaningfully execute the code?
other people to look at, modify, and meaningfully execute the code?

Xho
 
J

Joe Smith

David said:
I have (for example) a Perl script that connects to a database (or FTP site,
etc). The database (or ftp) password is either hard-coded (in clear text) in
the script or contained in an external configuration file (which must be
readable by the effective uid of the script).

I had a similar problem, but it involved using 'scp' instead of 'ftp'.
Public key entries in ~/.ssh/authorized_keys by themselves leave the
destination wide open to script viewers. I use this to restrict access:

#!/usr/bin/perl
# Name: /usr/local/bin/rrsync (should have a symlink in /usr/bin)
# Author: (e-mail address removed)
# Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys

use strict;
use warnings;
use Socket;
use constant LOGFILE => 'rrsync.log';
my $Usage = <<EOM;
Use 'command="$0 [-ro] subdir"'
in front of lines in $ENV{HOME}/.ssh/authorized_keys
EOM

my $ro = (@ARGV and $ARGV[0] eq '-ro') ? shift : ''; # -ro = Read-Only
my $subdir = shift;
die "No subdirectory specified\n$Usage" unless defined $subdir;

# The client uses "rsync -av -e ssh src/ server:dir/", and sshd on the server
# executes this program when .ssh/authorized_keys has 'command="..."'.
# For example:
# command="rrsync logs/client" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzGhEeNl...
# command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmkHG1WC...
#
# Format of the envrionment variables set by sshd:
# SSH_ORIGINAL_COMMAND=rsync --server -vlogDtpr . dir # push
# SSH_ORIGINAL_COMMAND=rsync --server --sender -vlogDtpr . dir # pull
# SSH_CLIENT=client_addr client_port server_port

my $command = $ENV{SSH_ORIGINAL_COMMAND};
die "Not invoked via sshd\n$Usage" unless defined $command;

my ($cmd,$dir) = $command =~ /(.* \.) ?(.*)/;
die "SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $cmd =~ /^rsync\s/;
die "$0 -ro: sending to read-only directory $dir not allowed\n"
if $ro and $cmd !~ /^rsync --server --sender /;

my $orig = $dir;
$dir = $subdir if $dir eq ''; # Use subdir instead of $HOME
$dir =~ s%^/%%; # Don't allow absolute paths
$dir = "$subdir/$dir" unless $dir eq $subdir or $dir =~ m%^\Q$subdir/%;
$dir =~ s%/\.\.(?=/)%__%g; # Don't allow foo/../../etc
$dir =~ tr|-_/a-zA-Z0-9.,|_|c; # Don't allow ;|][}{*?

if (-f LOGFILE and open LOG,'>>',LOGFILE) {
my ($mm,$hh) = (localtime)[1,2];
my $host = $ENV{SSH_CLIENT} || 'unknown';
$host =~ s/ .*//; # Keep only the client's IP addr
$host = gethostbyaddr(inet_aton($host),AF_INET) || $host;
$_ = sprintf "%-13s",$host;
print LOG "$hh:$mm $_ [$command] =",($dir eq $orig ? " OK" : "> $dir"),"\n";
close LOG;
}

exec "$cmd $dir" or die "exec($cmd $dir) failed: $? $!";
# Note: This assumes that the rsync protocol will not be maliciously hijacked.
 
S

Sébastien Cottalorda

David said:
I have (for example) a Perl script that connects to a database (or FTP
site, etc). The database (or ftp) password is either hard-coded (in clear
text) in the script or contained in an external configuration file (which
must be readable by the effective uid of the script).

Someone who was able to browse the code could easily determine the
password. That's a Bad Thing.

I could trivially obfuscate it (rot13, etc) but that would only thwart the
truly ignorant. The password could be symmetrically encrypted, but the
script somehow needs to determine the encryption key (and the idly curious
could determine this as well by reading the code).

How can I shield the database (ftp, etc) password from prying eyes?

What about using the Acme::Bleach perl module ?

Sebastien
 
S

Scott W Gifford

[...]
That said, if the threats are more dire, I'd recommend encrypting the
configuration files with GnuPG, and then decrypting/re-encrypting them
within your scripts via the --use-agent option. This necessitates
running gpg-agent as a daemon to automate the passphrase handling.
Once you get things set up, this approach is _very_ secure and fairly
easy to maintain. But it's probably overkill for what you're doing.

Interesting; I'm not really familiar with GPG's --use-agent option.
How does GPG get the passphrase to decrypt the config files? How does
GPG prevent another user from connecting to the daemonized agent and
having it decrypt the config file for them?

Thanks!

----ScottG.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top