views:

1045

answers:

6

We store all our application and db passwords in plain text in source control. We do this as our build/deploy process generates required configuration files and also does actual deploys that require these passwords (ie: running sql against a database requires you logon to the db using valid credentials). Has anyone had a similar need where you were able to implement this type of functionality while not storing the passwords in plain text?

A: 

If doing in C you could store in as an array of characters and put the characters in as decimal references. Not sure if this will break strings or not, but might help to alleviate some of that problem.

char pass[]={72, 101, 108, 108, 111};
Suroot
Boshfpngvba qbrf abg cebivqr frphevgl!
Schwern
eewwwwwwwwwwwww
Carson Myers
A: 

Store passwords in encrypted form. Write a custom routine that decrypts the passwords and updates the configuration files at build time. This can be easily integrated with the build tool like Ant.

Rahul
So where do you put the decryption key?
Schwern
A: 

You didn't mention the language, so here is a vb.net solution we use:

Imports System.Web.Security
Imports System.Security.Cryptography
Imports System.Text
Imports Microsoft.Win32

Public Class myCrypt

Private myKey As String = "somekeyhere"
Private cryptDES3 As New TripleDESCryptoServiceProvider()
Private cryptMD5Hash As New MD5CryptoServiceProvider()


Private Function Decrypt(ByVal myString As String) As String
    cryptDES3.Key = cryptMD5Hash.ComputeHash(ASCIIEncoding.ASCII.GetBytes(myKey))
    cryptDES3.Mode = CipherMode.ECB
    Dim desdencrypt As ICryptoTransform = cryptDES3.CreateDecryptor()
    Dim buff() As Byte = Convert.FromBase64String(myString)
    Decrypt = ASCIIEncoding.ASCII.GetString(desdencrypt.TransformFinalBlock(buff, 0, buff.Length))
End Function

Private Function Encrypt(ByVal myString As String) As String
    cryptDES3.Key = cryptMD5Hash.ComputeHash(ASCIIEncoding.ASCII.GetBytes(myKey))
    cryptDES3.Mode = CipherMode.ECB
    Dim desdencrypt As ICryptoTransform = cryptDES3.CreateEncryptor()
    Dim MyASCIIEncoding = New ASCIIEncoding()
    Dim buff() As Byte = ASCIIEncoding.ASCII.GetBytes(myString)
    Encrypt = Convert.ToBase64String(desdencrypt.TransformFinalBlock(buff, 0, buff.Length))
End Function

End Class
BenB
Our build/deploy process is ANT. Our application code happens to be Java.
Marcus
MD5? TripleDES? Damn, MD5 is already compromised and 3DES is on its way out. Use AES and SHA256. More importantly, once you've encrypted the login credentials, where do you put the decryption key? Chicken-egg.
Schwern
+3  A: 

I assume the objective is that you don't want your company's private passwords to be available, encrypted, decrypted, or otherwise, to anyone that should otherwise be allowed access to the rest of the source.

Here's how I do it. I've duplicated this pattern from TikiWiki, which does this too.

in some file that normally contains passwords, set them to dummy values, doesn't matter what. Set it to whatever your customer should see. Put a comment nearby for developers to leave this file alone and alter a second file.

In the second file, which gets created if it's not there, put the actual passwords. arrange for this file to be included, imported, whatever, by the first file.

Arrange for your source control to ignore that file. Could look something like this:

# in .gitignore
localsettings.py

# in settings.py
## Alter this value to log into the snack machine:
## developers: DON'T alter this, instead alter 'localsettings.py'
SECRET_VALUE = ""
try:
  from localsettings import *
except:
  pass

# in localsettings.py
SECRET_VALUE = "vi>emacs"
TokenMacGuy
+1  A: 

I've built systems where database userid/password pairs are not part of the code drop. The key is to setup a site-specific configuration mechanism. Then you can put such information on the box in question, without it being part of the code-base.

There's a bonus: you can not only have different passwords for different code drops, but also for different developers. :-)

staticsan
Good point. One scenario we have is where our deploy script runs sql against a db (could be dev, qa, prod, etc). All this gets done on a single deploy server. Not sure how to implement this solution in that case.
Marcus
The way to do that is for the sql-update script to run on the end-target server. Then it can use the local configuration to find the database. :-)
staticsan
+5  A: 

If your plan is to store all the code and configuration information to run a production system directly from version control, and without human intervention, you're screwed. Why? This is all just a violation of the old security axiom "never write your password down". Let's do a proof by negation.

First cut, you have plain text passwords in the configuration files. That's no good, they can be read by anyone who can see the files.

Second cut, we'll encrypt the passwords! But now the code needs to know how to decrypt the passwords, so you need to put the decryption key somewhere in the code. The problem has just been pushed down a level.

How about using public/private keys? Same problem as the passwords, the key has to be in the code.

The use of a local configuration file not stored in version control still puts the password, and the means to read them if they're encrypted, on disk and available to an attacker. You can harden things a little by ensuring that configuration file's permissions are very limited, but should the box be rooted you're screwed.

Which brings us to why putting passwords on disk is a bad idea. It violates the concept of a security firewall. One compromised machine containing login information means other machines will be compromised. One poorly maintained machine can tear down your whole organization.

At some point a human is going to have to inject the critical secret to start the chain of trust going. What you could do is encrypt all the secrets in the code and then when the system starts up have a human manually enter the key to decrypt all the passwords. This is like the master password system Firefox uses. It is open to abuse since once that one password is compromised, many systems may be compromised, but it is convenient and probably more secure since users only have to remember one password and are less likely to write it down.

The final touch is to ensure that should the login information be compromised (and you should always assume that it will be) that A) the attacker can't do much with it and B) you can quickly shut down the compromised accounts. The former means to only give the accounts as much access as they need. For example, if your program only ever needs to read from a database have it log in on an account restricted to SELECT. In general, remove all access and then add it only as necessary. Be stingy about the rights to delete lest you get a visit from little Bobby Tables.

The latter means you give each user/organization/project their own login, even if they can have the exact same rights and privileges and access the same data. It's a bit more of a hassle, but it means that if one system is compromised you can quickly shut down that account without shutting down your whole business.

Schwern