89

Java .class files can be decompiled fairly easily. How can I protect my database if I have to use the login data in the code?

Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
Jakob Cosoroaba
  • 1,702
  • 4
  • 24
  • 34
  • I hope you don't mind I retagged your question. I removed "username" and "password" and added "reverse-engineering" and "decompiling". I think they are more descriptive than the originals. Excellent question on the fundamentals, by the way! – William Brendel Jan 14 '09 at 13:25
  • 6
    Note that the fact that your're using Java isn't really relevent here. Having hard-coded passwords in any language is problematic in pretty much the same way ("strings thebinary" shows string constants in C programs just as well). – Joachim Sauer Jan 14 '09 at 13:28
  • @saua: True, but perhaps someone will post some sample code on how to decouple usernames and passwords in Java. I might even do that myself if I have the time. – William Brendel Jan 14 '09 at 13:32
  • I added some Java code demonstrating this. The code is really quite basic, but it should be enough to get someone started. – William Brendel Jan 14 '09 at 13:54
  • @Midday: Could you provide more information about your application? There seems to be some confusion in the comments. For example, where is this application being run? On a customer's machine? On a remote server? Local server? There might be bigger architectural problems depending on your answer. – William Brendel Jan 14 '09 at 14:31
  • 1
    I've noticed that a lot of answers think that you are trying to hide the username/passwords from an unauthorized user while the user running the app is ok. I believe you want to hide the password from *EVERYONE*. Please clarify this in the question. – pek Jan 14 '09 at 14:42
  • 1
    For example, say that the credentials are used to connect to a server that nobody other than the application can login. – pek Jan 14 '09 at 14:42

6 Answers6

126

Never hard-code passwords into your code. This was brought up recently in the Top 25 Most Dangerous Programming Mistakes:

Hard-coding a secret account and password into your software is extremely convenient -- for skilled reverse engineers. If the password is the same across all your software, then every customer becomes vulnerable when that password inevitably becomes known. And because it's hard-coded, it's a huge pain to fix.

You should store configuration information, including passwords, in a separate file that the application reads when it starts. That is the only real way to prevent the password from leaking as a result of decompilation (never compile it into the binary to begin with).

For more information about this common mistake, you can read the CWE-259 article. The article contains a more thorough definition, examples, and lots of other information about the problem.

In Java, one of the easiest ways to do this is to use the Preferences class. It is designed to store all sorts of program settings, some of which could include a username and password.

import java.util.prefs.Preferences;

public class DemoApplication {
  Preferences preferences = 
      Preferences.userNodeForPackage(DemoApplication.class);

  public void setCredentials(String username, String password) {
    preferences.put("db_username", username);
    preferences.put("db_password", password);
  }

  public String getUsername() {
    return preferences.get("db_username", null);
  }

  public String getPassword() {
    return preferences.get("db_password", null);
  }

  // your code here
}

In the above code, you could call the setCredentials method after showing a dialog askign for the username and password. When you need to connect to the database, you can just use the getUsername and getPassword methods to retrieve the stored values. The login credentials will not be hard-coded into your binaries, so decompilation will not pose a security risk.

Important Note: The preference files are just plain text XML files. Make sure you take appropriate steps to prevent unauthorized users from viewing the raw files (UNIX permissions, Windows permissions, et cetera). In Linux, at least, this isn't a problem, because calling Preferences.userNodeForPackage will create the XML file in the current user's home directory, which is non-readable by other users anyway. In Windows, the situation might be different.

More Important Notes: There has been a lot of discussion in the comments of this answer and others about what the correct architecture is for this situation. The original question doesn't really mention the context in which the application is being used, so I will talk about the two situations I can think of. The first is the case in which the person using the program already knows (and is authorized to know) the database credentials. The second is the case in which you, the developer, are trying to keep the database credentials secret from the person using the program.

First Case: User is authorized to know the database login credentials

In this case, the solution I mentioned above will work. The Java Preference class will stored the username and password in plain text, but the preferences file will only be readable by the authorized user. The user can simply open the preferences XML file and read the login credentials, but that is not a security risk because the user knew the credentials to begin with.

Second Case: Trying to hide login credentials from the user

This is the more complicated case: the user should not know the login credentials but still needs access to the database. In this case, the user running the application has direct access to the database, which means the program needs to know the login credentials ahead of time. The solution I mentioned above is not appropriate for this case. You can store the database login credentials in a preferences file, but he user will be able to read that file, since they will be the owner. In fact, there is really no good way to use this case in a secure way.

Correct Case: Using a multi-tier architecture

The correct way to do it is to have a middle layer, in between your database server and your client application, that authenticates individual users and allows a limited set of operations to be performed. Each user would have their own login credentials, but not for the database server. The credentials would allow access to the middle layer (the business logic tier) and would be different for each user.

Every user would have their own username and password, which could be stored locally in a preferences file without any security risk. This is called a three-tier architecture (the tiers being your database server, business logic server, and client application). It is more complex, but it really is the most secure way to do this sort of thing.

The basic order of operations is:

  1. Client authenticates with business logic tier using the user's personal username/password. The username and password are known to the user and are not related to the database login credentials in any way.
  2. If authentication succeeds, the client makes a request to the business logic tier asking for some information from the database. For example, an inventory of products. Note that the client's request is not a SQL query; it is a remote procedure call such as getInventoryList.
  3. The business logic tier connects to the database and retrieves the requested information. The business logic tier is in charge of forming a secure SQL query based on the user's request. Any parameters to the SQL query should be sanitized to prevent SQL injection attacks.
  4. The business logic tier sends the inventory list back to the client application.
  5. The client displays the inventory list to the user.

Note that in the entire process, the client application never connects directly to the database. The business logic tier receives a request from an authenticated user, processes the client's request for an inventory list, and only then executes a SQL query.

Grmpfhmbl
  • 1,119
  • 12
  • 24
William Brendel
  • 31,712
  • 14
  • 72
  • 77
  • 4
    How exactly does this keep someone from getting the username/password? Can't you just read it from the file then? – Joe Phillips Jan 14 '09 at 13:55
  • As I said in my answer, if your file permissions are set properly, only the user running the program has read access to that preferences file. In UNIX environments, this is done automatically. Windows might require additional steps (I'm really not sure, since I don't use Windows much). – William Brendel Jan 14 '09 at 13:58
  • I think the idea is that the user running the app isn't the one you are trying to keep it from. If that's the case, then you'd have to encrypt it. – Michael Haren Jan 14 '09 at 13:58
  • Yes, Michael is correct. Essentially the idea is that you already know the username/password, so there is no need to hide it from yourself. It will be hidden from other users, however, through file permissions. – William Brendel Jan 14 '09 at 13:59
  • @Michael - encryption won't help in keeping the password from the user running the app. It just pushes the problem onto trying to protect the key, and in any case the user will need some API somewhere to use the password. – frankodwyer Jan 14 '09 at 14:01
  • 7
    If you are deploying (example) a DB editing application to a user and you don't want them to know the database username and password, then you've architected the solution wrong, and the client software should be communicating with a server (via e.g., a web service) that does the DB stuff. – JeeBee Jan 14 '09 at 14:31
  • @JeeBee: Exactly correct. In my answer I assumed the user knows the credentials, and the problem is finding a way to store that information outside of the compiled code. Attempts to give *untrusted* users *trusted* access to any system will always fail. Nice comment, JeeBee. – William Brendel Jan 14 '09 at 14:36
  • I added more information to my original answer. It covers the basics of using a three-tier architecture, which is probably best for what the original poster wanted. – William Brendel Jan 14 '09 at 15:12
  • That's a lovely comprehensive answer indeed now. – JeeBee Jan 14 '09 at 19:33
  • I dont't quite understand your saying: "*Client authenticates with business logic tier using the user's personal username/password. The username and password are known to the user and are not related to the database login credentials in any way.*" The business logic tier is a web-service (written in java, php, etc.)? If so, where the user credentials are stored? Perharps in a config file in the web-service platform? But, what if we want to create new accounts to register new users? What then? Although, it's possible to hash these credentials and to send them over network to the business logic – John Astralidis May 20 '15 at 23:21
  • I think you are missing the main point of the article you are quoting. You don't just store the passwords in a file or database, you have to "store passwords outside of the code in a **strongly-protected**, **encrypted** configuration file or database". Otherwise, if u can set the right permissions on the passwords file, you could have set the same permissions on the .class you don't want people to decompile. – Tristan May 18 '17 at 18:40
  • How can same scenario be achieved with Node.js application? Can use Linux utility? – Nah Nov 06 '17 at 09:54
  • Out of curiosity, why not just store hashed credentials for an application in a file on a web server which can be grabbed using a password protected HTTP request? Naturally the 3-tier system will work better, but if that is not an option it seems that a Preferences file in Java would be better suited only to store the credentials needed to gather the hashed credentials from the server. This way nothing important is stored either in the application's binary or on a User's system – ViaTech Aug 07 '18 at 20:42
15

Put the password into a file that the application will read. NEVER embed passwords in a source file. Period.

Ruby has a little-known module called DBI::DBRC for such usage. I have no doubt that Java has an equivalent. Anyway, it is not difficult to write one.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
Keltia
  • 14,535
  • 3
  • 29
  • 30
  • 8
    While that makes it slightly easier to change the passwords later on, it doesn't solve the basic security issue. – Brian Knoblauch Jan 14 '09 at 13:21
  • Yes it does. See also the answer from William Brendel. – Keltia Jan 14 '09 at 13:23
  • 1
    The method Keltia and I pointed out is the accepted way of dealing with this problem. Decoupling your login credentials from your compiled code is one of the most basic software security practices. Putting the login credentials in a separate file is an effective way to achieve this. – William Brendel Jan 14 '09 at 13:27
  • Furthermore, the fact that your configuration information is in a plaintext file should be canceled by operating system restrictions. For example, in UNIX, the plaintext file should be owned by the user running the program and have permissions 0600, so only the owner can read it. – William Brendel Jan 14 '09 at 13:30
  • 5
    OK, so the file can only be read by the user running the program. Great. That solves nothing. :-) I, the user who we're trying to keep the password secret from, can read it just as easily as the app... – Brian Knoblauch Jan 14 '09 at 14:24
  • @Brian: You're trying to give *untrusted* users *trusted* access to a system, and you want it to be secure? That's just not possible. In that case, you really need to rethink your architecture. This is why copy protection doesn't work (it must give untrusted parties the ability to decrypt content). – William Brendel Jan 14 '09 at 14:29
  • This method will make the access more difficult, but by no means will protect anything. Even if the data is encrypted on file, the code can still be decompiled (and that is my main problem at this moment). So, i have to put sensible data on file, encrypt, and obfuscate the code that deal with encryption/decryption... – marcolopes Mar 09 '14 at 17:25
3

Are you writing a web application? If so, use JNDI to configure it externally to the application. An overview is available here:

JNDI provides a uniform way for an application to find and access remote services over the network. The remote service may be any enterprise service, including a messaging service or an application-specific service, but, of course, a JDBC application is interested mainly in a database service. Once a DataSource object is created and registered with a JNDI naming service, an application can use the JNDI API to access that DataSource object, which can then be used to connect to the data source it represents.

Tim Howland
  • 7,919
  • 4
  • 28
  • 46
3

No matter what you do, the sensitive information will be stored in some file somewhere. Your goal is to make it as difficult to get as possible. How much of this you can achieve depends on your project, needs and thickness of your company's wallet.

The best way is not to store any passwords anywhere. This is achieved by using hash functions to generate and store password hashes:

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366

Hash algorithms are one way functions. They turn any amount of data into a fixed-length "fingerprint" that cannot be reversed. They also have the property that if the input changes by even a tiny bit, the resulting hash is completely different (see the example above). This is great for protecting passwords, because we want to store passwords in a form that protects them even if the password file itself is compromised, but at the same time, we need to be able to verify that a user's password is correct.

Unrelated note: In the old days of the internet, when you click 'forgot my password' link, websites would email you your plain text password. They were probably storing those in a database somewhere. When hackers gained access to their database, they would gain access to all the passwords. Since many users would use the same password in multiple websites, this was a huge security problem. Luckily, nowadays this is not the common practice.

Now comes the question: what's the best way to store passwords? I would consider this (authentication and user management service stormpath's) solution a pretty damn ideal one:

  1. Your user enters the credentials, and this is validated against the password hash
  2. Password hashes are generated and stored, not passwords
  3. Hashes are performed multiple times
  4. Hashes are generated using a randomly generated salt
  5. Hashes are encrypted with a private key
  6. Private key is stored at a physically different place than hashes
  7. Private keys are on a time-based fashion updated
  8. Encrypted hashes are divided into chunks
  9. These chunks are stored in physically separate locations

Obviously you're not the google or a bank, so this is an overkill solution for you. But then comes the question: How much security your project requires, how much time and money you have?

For many applications, although not recommended, storing hard-coded password in the code might be a good enough solution. However, by easily adding couple of extra steps of security from the above list, you can make your application much more secure.

For example, let's assume step 1 is not be an acceptable solution for your project. You don't want users to enter password every time, or you don't even want/need users to know the password. Still you have sensitive information somewhere and you want to protect this. You have a simple application, there is no server to store your files or this is too much hassle for your project. Your application runs on environments where it is not possible to have files securely stored. This is one of the worst case, but still with some additional security measure you can have much safer solution. For example, you can store the sensitive information in a file, and you can encrypt the file. You can have the encryption private key hard coded in the code. You can obfuscate the code, so you make it a bit more difficult for someone to crack it. There are many libraries exists for this purpose, see this link. (I want to warn you one more time that this is not 100% secure. A smart hacker with right knowledge and tools can hack this. But based on your requirements and needs, this might be a good enough solution for you).

Caner
  • 57,267
  • 35
  • 174
  • 180
1

This question shows how to store passwords and other data in an encrypted file: Java 256-bit AES Password-Based Encryption

Community
  • 1
  • 1
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • 1
    Somewhere in source code still need to decrypts encrypted password to create connection, This considered password is still there. – Bear0x3f Feb 11 '17 at 06:38
0

MD5 is a hash algorithm, not an encryption algorithm, in short u cant get back wat u hashed, u can only compare. It should ideally be used when storing the user authentication information and not db username and password. db username and pwd should be encrypted and kept in a config file, to do the least.

renegadeMind
  • 4,073
  • 5
  • 29
  • 37
  • I've heard of people who generate all possible combinations of strings and store their corresponding MD5 hashes. So when they find somebody's MD5 hash, they just find the hash they stored, and they get the corresponding string. – Nav Feb 23 '16 at 11:18