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

Esteemed monks, I am writing a series of CGI scripts that tie into a backend Oracle database. My question regards storing the web user's database username and password, by which I mean not the individual users login/password information but the database login/password used by the CGI scripts to run queries, insert records, etc. Right now I have this information sitting in a text file outside the web directory heirarchy on the Apache server. Are there alternate strategies for storing this information securely?
  • Comment on Securing the database password for web applications

Replies are listed 'Best First'.
Re: Securing the database password for web applications
by FitTrend (Pilgrim) on Mar 08, 2005 at 18:26 UTC

    Security is always an issue with our Web Based Applications. We have an account that can read/write to the various databases and tables that our applications create within our framework. We use a MySQL backend. We have a table within one of our databases that contain a list of accounts (user/pass). The passwords have been encrypted.

    To connect to the database initially and verify the user/pass, we use a db account (user/pass) that is configured via an outside config file that can only read this table that contains the list of accounts and encrypted passwords. Once we connect to the database with this account (from the conf file), it verifies the user/pass using an encryption/decryption perl module. If a successful match is found, we then connect to the database with that account.

    Of course there are several perl modules on CPAN that allow you to choose the encryption/decryption method that fits you best.

    Hope this helps

Re: Securing the database password for web applications
by b10m (Vicar) on Mar 08, 2005 at 18:39 UTC

    I've asked a similar question in the past. You might want to read up on that.

    --
    b10m

    All code is usually tested, but rarely trusted.
Re: Securing the database password for web applications
by RazorbladeBidet (Friar) on Mar 08, 2005 at 18:26 UTC
    Just basically setting the right permissions on the txt file and possible encryption is all I can think of.
    --------------
    It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Securing the database password for web applications
by sgifford (Prior) on Mar 09, 2005 at 03:57 UTC
    Three thoughts.

    First, what you're doing is about as secure as you can get with a standard shared server. If your hosting provider does a good job of isolating the users from each other, then it's fairly reliable as long as your code is secure. If it's not, consider whether the data you're protecting is valuable enough to pay for more isolated hosting, either with a higher-quality shared host that uses suEXEC and chroot, or with a private server or virtual private server. As others have mentioned, ideally you'd want to use a dedicated user account for the parts that have to read the database, so that security flaws in other parts won't compromise the password. Think in terms of minimizing the exposure of the data, and isolating the parts that need access to it.

    Second, make sure your code is secure. Use taint mode, and carefully review your code with an eye towards how somebody could compromise it.

    Third, one possibility is to use Oracle usernames/passwords as the system logins, so the user simply authenticates to the database on login. That way no password has to be stored on the system at all. I did this for a recent project, and was quite happy with the results.

Re: Securing the database password for web applications
by tirwhan (Abbot) on Mar 08, 2005 at 19:01 UTC

    Create separate system user accounts for each database user and use suEXEC. Then place the passwords into the user's home directory, readable only by that user

    That way, even if one account gets compromised somehow, the attacker can only read the database password of this individual user.

      That's often impractical for web applications, because:

      1. You need a lot of system accounts
      2. You need a lot of home directories
      3. You need a lot of database connections

      For number 3, you need one connection per user. Under mod_perl+Apache::DBI, those connections stay open, but that inevitably leaves a lot of connections open that aren't being used. That's a lot of wasted memory. Preferably, you have exactly one connection per database.

      So this solution simply doesn't scale.

      "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

        That depends on your authentication mechanism and authorisation model.

        • If you have a small number of users it's a non-issue.
        • If you have a larger number of users but small number of database users (aka authorisation groups) the HTTP user should not be identical with your webapp user, instead you have one apache user for each level of authorisation you want to give. You receive the HTTP authentication header, use your own method of authenticating the user, then set the HTTP user to be your database/system user. That way, you can have a different HTTP user for, say, admin, user and guest and each of these will only have access to their own database passwords.
        • If you have a large number of database users you are entirely correct, my solution doesn't scale and you should do something else.
Re: Securing the database password for web applications
by jbrugger (Parson) on Mar 08, 2005 at 18:29 UTC
    Loads of them, but it seems to me, it all depends on what you really want. What type of app is it, what kind of rights do you want, are there different type of users, do they need different times to log in, do they have different roles etc. etc.
    But anyway, you're able to use .htacces and .htpasswd in apache, use the dbd implementation and modperl to inplement it in apache, use ldap, or use dbd and your database to use your own script to take care of it.
    For our application we use a simple database table with a crypted password, but it's accessed through the user object, so per user we can set certin rights depending on the role the user has on a certin moment.
    The user settings are then stored using a session cookie, so it's allways known if a request is permitted or not.
    ps. we use MySQL, and use the sql command 'crypt' to crypt the data. When using https it should give enough security i'd say.
Re: Securing the database password for web applications
by hardburn (Abbot) on Mar 08, 2005 at 21:13 UTC

    If you don't mind having to reset the password instead of giving the old one when a user forgets what their password is, here is what you can do:

    p = plaintext password salt = random value at least 32 bits in size hash() = cryptographic hash function c = hash( salt + hash( salt + p ) )

    Store c and salt in the database. When you want to authenticate, take the salt from the database and the password you got from the user, run it through the same function above (hash( salt + hash( salt + p ) )), and compare it to the value of c in the database. If they're equal, the authenticationis successful.

    This makes it cryptographically impossible (read: extremely difficult) for anyone with access to the database to know what the orginal password is (this is also why you have to reset the password when the user forgets).

    SHA256 or SHA512 are good hashes to pick for now, though recent findings suggest that they're not as good as we thought they were. We don't have any good alternatives right now, and they'll be fine for the forseeable future. Avoid MD5 like it was Microsoft's Paperclip.

    When designing the database, I suggest making the column a variable-length text field (like TEXT under PostgreSQL) with no hard limit on the length and put in some kind of text encoding (like base64). You may also want to store what algorithm was used to hash the password. That way, when we finally do have an alternative to SHA, you can switch over with no changes to the database.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

Re: Securing the database password for web applications
by jhourcle (Prior) on Mar 09, 2005 at 03:41 UTC

    It all depends on what you consider to be 'securely'. For instance, you can use an approach where the server prompts for it on startup, and stores in in memory. Although you then don't have the password in a file, someone can still either sniff your network connection, or force a coredump to recover the password. There's also the inconvenience of needing to have human intervention when the service starts.

    As a similar alternative, you could store the config in a perl module under mod_perl, and have something else trigger to store the authentication info in the module, which would then be accessible to other programs.

    Both of these have the problem that they assume that the whole server is to have access to the database. If you're on a multi-user system, this would be quite bad.

    Of course, storing the database connection info in the server is sort of what ColdFusion does. I haven't used it in many years, but up through at least 4.5, the system kept a registry of connection information, and anyone who knew the database connection's name could make use of it.

    Other alternatives would be to use Oracle Advanced Security and use some other authentication scheme -- at the very least, ensuring that the user in question can only connect from the web server in question. (even if you use IP filtering of some sort, you can ensure that the user is keyed to a particular host)

    You could also store the information remotely, and poll for it, rather than keeping it stored locally ... but you still have issues with how you keep the characteristics of the polling secured, which defeats the purpose for the most part.

    I think the important thing to remember is that there is no true 'securely' when it comes to security. You can make things less likely to be cracked, but there is no such thing as unbreakable. If you have to authenticate, it can be sniffed. Even if you were to find some way to pass into the authentication system the path of the calling script, so you could restrict database access to particular directories, I'm guessing there'd be some way to fake it.

    You're probably better served by logging access on the database, and spend time reviewing the logs, or writing scripts to parse the logs and look for irregular activity.

    Talk to your security folks and your DBA -- odds are, there are other things that you can do to reduce risk -- make sure that the database user had the bare minimum access that it needs, and that you're regularly looking over the logs for sign of improper activity.