Password storage in source control
Asked Answered
D

6

19

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?

Derrickderriey answered 18/2, 2009 at 2:21 Comment(1)
Put the passwords in o/s user environment variables.Abatement
C
21

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.

Chandigarh answered 18/2, 2009 at 2:22 Comment(4)
"but should the box be rooted you're screwed" I'm confused – are there security protocols where being rooted is part of the threat model? I can't imagine how you would possibly defend against a root attack.Groomsman
@Groomsman When one system is penetrated, you want to make sure they can't use that to penetrate another system. In this case, if you store your database password on disk and a single machine is penetrated, the attacker can now access your database. I am assuming the application code and database are running on different servers. Also you don't need to be root to read the application config file, you just need to be the application user which is much easier. You don't even need that, you just need to fool the app into letting you view its config file.Chandigarh
if your system is penetrated, how is it possible to keep the attacker from reading the password? Saving it to the filesystem is easy to read via FS I/O, saving it to an environment is easy to read via /proc/, and saving it to the RAM is easy to read via /dev/mem. What alternative are you suggesting?Groomsman
@Groomsman Store all the passwords encrypted. When the process starts, enter the key to decrypt them. It will only be in memory. While reading /dev/mem may be easy once you have root, finding something specific in there is not; certainly significantly more difficult than reading it from a file. This is my understanding of how keychain servers work. This is certainly better than having clear passwords in source control checked out to a bunch of dev machines. For a more definitive answer, ask on Security.SE.Chandigarh
S
6

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"
Soche answered 18/2, 2009 at 2:42 Comment(0)
S
1

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. :-)

Saccular answered 18/2, 2009 at 2:51 Comment(2)
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.Derrickderriey
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. :-)Saccular
H
-1

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
Hengelo answered 18/2, 2009 at 2:34 Comment(2)
Our build/deploy process is ANT. Our application code happens to be Java.Derrickderriey
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.Chandigarh
A
-4

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.

Ashley answered 18/2, 2009 at 2:29 Comment(1)
So where do you put the decryption key?Chandigarh
C
-8

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};
Cauvery answered 18/2, 2009 at 2:25 Comment(1)
Boshfpngvba qbrf abg cebivqr frphevgl!Chandigarh

© 2022 - 2024 — McMap. All rights reserved.