http://www.perlmonks.org?node_id=975271

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

Hi Monks,

How do keep passwords safe in an interpreted language like perl?

OK, maybe you start off by keeping them in an encrypted file, but as soon as you read them into a variable, they become visible.

What to do.

Regards

Steve.

Replies are listed 'Best First'.
Re: Keeping a password safe.
by moritz (Cardinal) on Jun 09, 2012 at 03:07 UTC

    You cannot keep secrets from a user with system level access. It's as simple as that. And that's not unique to interpreted languages like Perl, it applies to native code too.

    What you can do is provide a webservice where the secret stays on server and never reaches the client.

      Hi Moritz,

      Thanks for response.

      I guess it's true to some extent. It's interesting that Windows, where you don't have access to the source code, generally has more security issues than Linux where you do. But even with Windows you have to be a serious hacker to get into it properly: I couldn't do it, for example.

      I don't need bank-level security with remote chip and PIN, however, some ordinary commercial-grade security would be nice.

      Regards,

      Steve

        Your analogy misses an important point. To compromise a windows system, you have to find a new vulnerability, which isn't easy.

        But to get access a password that a program uses for accessing an FTP server, all one has to do is to monitor the network traffic. There are even tools that automatically sniff out passwords from traffic dumps.

        Even if you use a more sophisticated approach (like ftp over ssl), the password needs to be in plain text in the memory of your application, and using a debugger it's not hard work to find it out.

        So since the technical avenue is closed for you, I'd recommend to hand out the passwords to your users, and forbid them (in your terms of service) to give it to third parties. Since you want to protect the downloads, I infer that you sell your software commercially, so you already have some form of direct contact with your customers.

        If you want to be a bit more careful, give out different passwords to different users, so that you can easily diable one of them if you suspect abuse.

        Note that any "clever" solution which tries to obfuscate the password will make debugging much harder in case something goes wrong (and something always goes wrong).

Re: Keeping a password safe.
by bitingduck (Chaplain) on Jun 09, 2012 at 04:42 UTC

    Passwords for what purpose?

    If you're storing them in a keychain, then the best you can do is encrypt them (preferably salted) and only decrypt as little as you need to use them. But as moritz says, anybody with system access can get to them.

    If it's passwords supplied by users that you're storing to authenticate them later, you salt them and hash them with a one-way function and store that, then for authentication you take the user input, apply the salt and one way function and compare that with the stored one. You can make things harder by making the hash take longer.

Re: Keeping a password safe.
by flexvault (Monsignor) on Jun 09, 2012 at 14:06 UTC

    Steve_BZ,

    Could you explain further, like 'web https passwords' or 'ssh passwords' or 'telnet passwords' or '. . .'

    If you talking about web authorization, then you could use javascript and Perl to encode the password, but still all depends on some physical security to a degree.

    And like what was already said, anybody with system administrator access can get to them.

    "Well done is better than well said." - Benjamin Franklin

      Hi Flexvault,

      I have a Perl app to which I wish to supply maintenance and other updates from an FTP site. I want the FTP site to be secure and to use an ftp user name and password to access the site, but I want this to be stored in such a way that the password is secure.

      Regards

      Steve

        Here's the problem: there's no such thing as "stored in such a way that the password is secure." If your program can get at the password and use it without need for any manual input, then anyone who gains access to your program can do the same. You can do a certain amount of obfuscation so no one will stumble across the password accidentally, but that's not actual security, and it won't stop a determined invader. You could run the password through six kinds of reversible encryption, chop the result up into individual bytes, and hide each byte into a different spot in a JPEG image in a hidden directory; but if your program knows how to reverse the whole process and get the password, anyone who gains access to your program can do it too.

        The same thing is true of SSH private keys, by the way. They're better because they avoid sending passwords across the network, not because their local storage is any more inherently secure. (SSH keys can be protected by requiring a typed-in passphrase, but presumably you don't want to require human input every time you run this script.)

        So the place to worry about security is not within your application or how it stores its passwords, but in how secure your system is at the network, user, and physical level. If the system is on a network, then network security is necessary to make sure no one can get at your application and private data that way. If there are other users on your system, you have to make sure those users don't have access to your files. If they can't read your password file, it really doesn't matter whether your password is cleartext or obfuscated. At the physical level, if other people use your computer, you may need to take steps to make sure they can't access your program from the console, even by rebooting.

        Take care of those levels of security, and you'll have nothing to worry about. Ignore them, and your passwords won't be secure, no matter how you store them.

        Aaron B.
        Available for small or large Perl jobs; see my home node.

        Plain old FTP isn't very secure-- it generally sends the authentication in cleartext. If you can set up the server to use SFTP then it will be more secure, and you can also set up ssh key pairs for authentication so that you don't have to send a password when you login- when you ssh, scp, or sftp into the server, the ssh program at your end handles authentication via the keypairs. This is particularly convenient if you want to have a pair of computers talk to each other on a regular basis without human intervention. For an example, I have a web scraper that runs at home and generates database inputs from its scrapings that it uploads to the server on its own a few nights a week. I have a few of my accounts set up with ssh keys, and it's pretty convenient.

        Setting up ssh keypairs isn't hard, but I don't do it often enough to have it at my fingertips-- I look it up every time. Here's an example of how to do it (first hit on google). It then depends on the general security of the machines at either end.

        Steve_BZ,

        You already have some good answers, but I get the feeling you are asking specific questions about a bigger problem. I searched on some of your previous posts and came up with this.

        These are my limitations: * It does not need to be synchronous (although it can be). * It is running behind a router or firewall *(this means I probabl +y can't log on to it)... * It should provide a log of activity that can be analysed or uplo +aded to a server later.

        Is this still the problem your working on?

        Thank you

        "Well done is better than well said." - Benjamin Franklin

        I think a better step is to minimize the power of the information that needs to be exposed to the client. If the client needs to upload files to the FTP server, then give the client access only to upload files and only the files it should be updating. And make that access only work when exercised from the system where the client is run.

        If your FTP server software doesn't support such fine-grained access control, then have the client upload via some other means. You can configure ssh such that connections using a specific key file only allow very specific actions and only from certain IPs. On my OS, "man authorized_keys" (like http://man.he.net/man5/authorized_keys) gives details.

        If the FTP server can even verify the uploaded files in some way, that may also be worth implementing. You could place restrictions on the naming and size of the files. You could examine the files to verify that they appear to be the correct type of file. Perhaps whoever is providing the files to the client could also provide cryptographic signatures for the files that the FTP server would verify. You could have the server send out an e-mail notice if rejected files get uploaded.

        If you think this client is actually likely to be an attack vector, you could even honey-pot the client such as by giving it an 'access list' that it uploads if it gets updated. But never update this file and have the FTP server e-mail if such an update is received (and the FTP server doesn't actually honor the access list, just to be clear).

        You could also have the FTP server send notifications of any updates to a third location so you can periodically review the pattern of updates for unexpected activity (if anybody will actually continue to bother to do that).

        etc.

        Also, you should run the client from a relatively secure host. Don't run the client from a shared-hosting service, for example. A better choice is a host that requires one layer of authorization just to get through the firewall (such as a VPN) and that has few logins permitted.

        (Though, I was a bit surprised and disappointed that a recent employer had the VPN using LDAP authentication so somebody getting hold of my corporate username and password could get through both the firewall and into hosts behind the firewall -- though I suspect their motivation was certainty of timely revocation of all access upon termination of employment.)

        I doubt your specific upload access case is serious enough of a security concern for even most of these steps to be warranted. But at least you've got a large list to pick from, if you so choose.

        - tye        

Re: Keeping a password safe.
by Khen1950fx (Canon) on Jun 10, 2012 at 06:23 UTC
    Here's an interactive script that uses Term::ReadPassword and Digest::MD5. This is just to give you an idea of what to do. It creates a 128-bit message digest of the inputted password.
    #!/usr/bin/perl -T BEGIN { $| = 1; $ENV{'USE_STARS'} = 1; } use autodie; use strict qw/refs subs vars/; use warnings FATAL => 'all'; use Term::ReadPassword; use Digest::MD5 qw(md5_base64); if ( $ENV{'AUTOMATED_TESTING'} ) { print "Automated testing detected"; exit; } $Term::ReadPassword::USE_STARS = 1; local (*TTYOUT); my ( $in, $out ) = Term::ReadLine->findConsole; die "No console available: $!" unless $out; if ( open TTYOUT, '>>', $out ) { print "Opened TTYOUT: "; } else { die "Couldn't re-open STDOUT" unless open TTYOUT, '>>', &STDOUT; } select( ( select(TTYOUT), $| = 1 )[0] ); INTERACTIVE: { my $secrect = ''; my $new_pw = ''; { print TTYOUT "\n\tThis is a 'fake' password test\n\n"; my $new_fakepw = read_password("Enter your 'fake' new password +: \n"); if ( not defined $new_pw ) { print TTYOUT "\tNo password entered\n"; next INTERACTIVE; } else { my $secret = $new_pw; print TTYOUT "\t Your 'fake' password is now changed \n"; } } my $salts = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 + . /"; my $password = $new_pw; my $key = "justakey"; my $s1 = rand(64); my $s2 = rand(64); my $salt = substr( $salts, $s1, 1 ) . substr( $salts, $s2, 1 ); my $encrypted_password = $salt . md5_base64("$salt/$password / $ke +y "); #To verify this password, we would use: use Digest::MD5 qw(md5_base64); $salts = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 + . /"; my $entered_password = $password; $key = "justakey"; $salt = substr( $encrypted_password, 0, 2 ); my $pw2 = $salt . md5_base64("$salt/$entered_password / $key "); if ( $encrypted_password eq $pw2 ) { print "\nApplying digest...\n"; print "\t Passwords match\n "; } } close TTYOUT;

      I understand this is an example only, but MD5 is no longer considered cryptographically secure, and new projects probably shouldn't be using it. There are several alternatives, and thanks to CPAN they're just about as easy to use as MD5. Nowadays it seems the general consensus is leaning toward SHA2-256 or SHA2-512, or somethig from AES (Rijndael).


      Dave

Re: Keeping a password safe.
by DrHyde (Prior) on Jun 11, 2012 at 10:52 UTC
    Same as you would in any other language - keep the plain-text in memory for as little time as possible, overwrite the variable once you no longer need it (before free()ing or, in perl, letting it fall out of scope), try to prevent it from being written to swap (kinda tricky in perl - look for wrappers around mlock(2)).

    A password in a variable in a C program is also visible - to a user using the debugger, or a user who can make your program dump core, or a user who can look at whatever your platform's equivalent of /proc/$PID/mem is.

Re: Keeping a password safe. (database / PostgreSQL)
by erix (Prior) on Jun 12, 2012 at 13:11 UTC

    In the case of worries about a postgres database-password the following is possible to connect without password (linux, unixen):

    1. Use a ~/.pgpass file, or a customised copy somewhere (e.g. you could use the name name "$HOME/.pg_$USER"), and reduce access to it with chmod 0600 (in fact, in won't work otherwise). (see [1])

    2. Point environment variable PGPASSFILE to a customised .pgpass-like file).

    3. To make matters easier, you can also set PGPORT, PGHOST, PGDATABASE (if they are different from the defaults, which are resp. 5432, /tmp, $USER).

    psql et al (all clients based on libpq) can now connect via these variables (e.g. perl DBI will connect with the minimal dsn 'dbi:Pg:').

    [1] pg manual: libpq-pgpass.html

    [2] pg manual: client-authentication.html

    UPDATE: thanks to moritz for reminding me to add PGDATABASE.