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

I am authoring a web application that connects (via DBD::ODBC) to an external SQL-Server database. By external, I mean not on the same subnet. This connection requires authentication, since no anonymous or guest access is allowed by the SQL Server (a good thing).

What I'm running up against is a pair of conflicting policies that result from stupidity in system architecture (over which I have no control). Because of settings I cannot change, and the admins will not change, integrated authentication to the SQL server will not work. All well and good, as I have been given a SQL Server login -- I just have to supply the username and password via the DBI->connect() construct. Even the fact that the password is in the clear is OK, because the link is over an IPSec-protected connection and so encrypted.

However, it is against policy to store a password in clear text in the registry, config files, or code. Packing with PAR doesn't exempt me, as the policy specificially names source code. So, I have to use a SQL ID because of one policy, but I can't store it in the clear because of another. I've already tried to get one of these policies excepted for this app, but no luck.

I have been stumped -- I pray my fellow monks can give me ideas as to how to approach storing a password in a secure way, without storing keys or passwords in the clear, and without requiring user interaction. It seems like an impossible task, but then it might just be my frustration.

Thank you in advance for any insights provided.

Update: Thanks to kutsu and graff for ideas that combined for my solution. I used Data::UUID to generate a "SID" (not really, but close enough) for my app which is used as a key to decrypt the password from a registry entry (using Win32::TieRegistry, Crypt::CBC as an interface to Crypt::Blowfish). SIDs are exempt from the key-storage rule for obvious reasons, thanks to graff for getting me thinking along those lines.


The Eightfold Path: 'use warnings;', 'use strict;', 'use diagnostics;', perltidy, CGI or CGI::Simple, try the CPAN first, big modules and small scripts, test first.

  • Comment on Security: balancing two conflicting password policies

Replies are listed 'Best First'.
Re: Security: balancing two conflicting password policies
by graff (Chancellor) on May 13, 2005 at 01:12 UTC
    Do you have the ability to set the password yourself for the SQL Server login? If so, consider the following:
    1. Come up with a string that is derivable from some concatenation of perl's predefined variables (e.g.  $<.$0.$^O or some such) -- use anything you can that "localizes" the string but keeps it invariable when the script is run as intended by the authorized user(s).
    2. Get the MD5 signature of that string (formatted as base64), randomly select some subset of characters from the signature and put them together in some way to make the password.
    Now all you have to do is write the script to derive the password in the necessary fashion, and bingo -- your password is generated at runtime.

    I suppose that could be construed as skirting the official policy, but you can point out truthfully that the stated policy conditions are met: the password is not stored as clear text in source code, config file or registry. (It's built on the fly via variables that are likely to have unsuitable values if the script is usurped.)

    If you are not able to change the password, play with a few different ways of deriving a string, until you find one such that a base64 MD5 sig contains the characters that make up the password, and build some suitably obfuscated way of pulling those characters in the needed order out of the sig.

      ++ I used a similar approach (using predefined perl vars to create the password) at a previous job, and was able to pass it by management there, and at corporate level.

      It's like any other lock though, it only keeps honest people honest. Nothing is 100% secure.

      If you give a man a fish he will eat for a day.
      If you teach a man to fish he will buy an ugly hat.
      If you talk about fish to a starving man, you're a consultant.
Re: Security: balancing two conflicting password policies
by dragonchild (Archbishop) on May 12, 2005 at 19:21 UTC
    Ask said admins for guidance as to what you should be doing. I'm sure you're not the only application that is required to jump through these hoops.

    If they bring up the compiled/interpreted canard, I would point them to your favorite hexdumper and say "Compiled means you can't read it in Word. It doesn't mean 'encrypted'."

    I've found that BCC'ing your manager on these discussions usually doesn't hurt, either.


    • In general, if you think something isn't in Perl, try it out, because it usually is. :-)
    • "What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?"

      Sadly, I am the unique case. I'm in this boat because they won't buy hardware or pay to move the hardware they "found" for me into the datacenter.

      As for the compiled/interpreted -- that's not really at issue here. The policy not to have cleartext passwords in source is good; I tried to get an exception in this case because I can't use the recommended alternative. I tried to suggest that 'masking' it by using PAR, PP, etc. might be sufficient in this case. No deal - I'm conflicted, because it was the right call for them to make but it's making my life hell. ;-)


      The Eightfold Path: 'use warnings;', 'use strict;', 'use diagnostics;', perltidy, CGI or CGI::Simple, try the CPAN first, big modules and small scripts, test first.

Re: Security: balancing two conflicting password policies
by danb (Friar) on May 12, 2005 at 23:33 UTC

    ...how to approach storing a password in a secure way, without storing keys or passwords in the clear, and without requiring user interaction. It seems like an impossible task...

    You hit the nail on the head. It is impossible (1). Since they probably don't think it's impossible, they must think that compiling a program is the same as encrypting it. It's not, just as dragonchild said above. In fact, if they think that is secure, they might be impressed if you told them that your entire application is ROT-26 encrypted.

    Furthermore, even if they changed the policy so that it was possible to comply with by allowing you to store the private key in plain text, then it would still not increase the security of the credentials very much. Because then all a cracker has to do is get the plain text private key.

    In other words, at some point, something has to be stored in plain text. You can encrypt it 10 times and 9 of the private keys will be encrypted, but the last one has to be plain text. That might delay a script kiddie, but I wouldn't put much stock in that defense.

    The only way to keep someone from getting the credentials is plain old security. It doesn't matter if it's in the source code, binary, configuration file, or what. If a cracker gets into your system and can read the password and the private key, then it's game over.

    So you have to focus on preventing crackers from getting the password file and the private key file. Good luck in dealing with this situation (ugh, and the politics).

    (1) OK, actually it is possible. But you would need a Cray super computer. Because instead of storing the private key in plain text, you would have to run a brute force decryption crack program to get the contents of the encrypted passwords every time your app starts up.

    Or, instead of encrypting the password, you could store it in the middle of some really bad VB code. While reading the code, the cracker would go clinically insane before he finds the password.

    -Dan

      It's not impossible, it's just improbable. ;-)

      We've had this discussion before. And my answer was to not store passwords at all. The difficult part, of course, is that this would require changing database servers - probably just as much of a beaurocratic nightmare, if not moreso, than what the OP is facing already.

      This kinda reminds me of the old maxim: fast, working, cheap - pick two. Here it is: secure at the front, secure at the back, database that requires userid/password to be secure - pick two. And, like management making the first decision, management here is likely to say "All three!" as if just decreeing it changes the laws of physics.

      (And here I go, revealing a bit more about my life by the assumptions that I make in my answer...)

        Just store it in a hidden system file, then its not in the application code:)

        If the user account is restricted by host ip using database privileges and only granted what it needs the worst that happens upon password discovery is your application data gets compromised if someone gets on the box.

        If someone is on the box they can most likely get your encryption keys and code as easily as they can get the password so the encryption wont help much
Re: Security: balancing two conflicting password policies
by kutsu (Priest) on May 12, 2005 at 19:14 UTC

    Use a Crypt module to record the password (in a file or the source), I'd use Crypt::Blowfish for this myself, and then then uncrypt it before connecting to the SQL server. Another idea, you say you can't use PAR because of a source issue, does this exclude PP?

    Update: Submited before adding PP info.

    "Cogito cogito ergo cogito sum - I think that I think, therefore I think that I am." Ambrose Bierce

Re: Security: balancing two conflicting password policies
by crashtest (Curate) on May 12, 2005 at 21:10 UTC
    ... it is against policy to store a password in clear text in the registry, config files, or code.
    It seems to me [id://kutsu]'s suggestion of using Crypt::Blowfish complies fully with this policy. I work on applications that handle sensitive data (like database passwords in config files) the same way.

    That doesn't mean you're completely secure though. If you haven't already, check out Quest: a bulletproof-secure, automated scraper for an interesting discussion on safely storing and using sensitive data.

Re: Security: balancing two conflicting password policies
by fizbin (Chaplain) on May 13, 2005 at 05:26 UTC
    As others have pointed out, following the spirit of this policy is impossible. However, following the letter of the policy may not be impossible, and in fact could be as simple as this:

    Store in your code two strings of the same length, some length longer than the password. At runtime, xor the strings together using perl's a-string-is-a-bitvector feature. The strings will have been chosen so that the result is the desired password.

    Okay, that's one level. Now, what I would suggest is that you in addition write a script that prompts for a password, and mangles some other script to include the password as two variables as above. (Probably through something as simple as s/__RANDOM_STRING__/$randstr/; s/__PASS_XOR_RAND__/$pass^$randstr/e;) Then, this automatically runs pp over the mangled version, and deletes the mangled script. Call this second script your "build script".

    This has the advantage that the password is in plaintext only in the memory image of the running program, and is not even deriveable from the source as it sits in your source control. The password is deriveable from the compiled executeable, but that's a necessity.

    Of course, you don't need to use xor "encryption"; this method can easily be adapted to use Blowfish or AES or some other cryptographic standard that sounds impressive. (But really, what do you gain?)

    Anyone ever think that some policy like this is behind the rot13-encrypted data in the windows registry?

    -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/
Re: Security: balancing two conflicting password policies
by eejack (Hermit) on May 12, 2005 at 23:25 UTC
    Could you write a daemon that holds the connect information ( the password etc. ) that gets that connect information via prompt - therefore the information needs to manually entered on server startup or perhaps entered into a short compiled script?
    EEjack

      That would be a great and secure way to do it... except that you must have missed the last little part his message:

      ...and without requiring user interaction.

      -Dan

Re: Security: balancing two conflicting password policies
by Miguel (Friar) on May 13, 2005 at 10:19 UTC
    If an intruder can access your source code, on your server, your _real_ problem is not the way you store your passwords.
Re: Security: balancing two conflicting password policies
by derby (Abbot) on May 13, 2005 at 13:04 UTC
Re: Security: balancing two conflicting password policies
by wazoox (Prior) on May 13, 2005 at 10:47 UTC
    OK, my own silly suggestion : uuencode the password in the config file. It's not clear text, is it? :)