4

I have a piece of python code, it uses MySQLdb to connect to a database. The username/password are in the script in plaintext. I want to deliver this code to client but do not want them to know the username/password. What is the best way to do that? If the MySQLdb module can be packaged as well, it would be even better. Let us assume it is on Linux and the client has standard Python interpreter. It does not need to be super safe, not disclosing the username/password in plaintext is good enough. The client need to have Write permission to our database. But the Write operation can only come from our program, we do not want the client to write in arbitrary way.

szli
  • 36,893
  • 11
  • 32
  • 40

5 Answers5

4

Normally, obfuscating passwords is a very bad idea, for the reasons Erik A. Brandstadmoen explains. This is exactly why every DRM solution—DVD-CSS, Blu-Ray HDCP, Flash RTMPE, etc.—eventually fails. On the other hand, sometimes it's necessary for business or legal reasons, which is exactly why all those DRM solutions were invented in the first place.

You say, "It does not need to be super safe, not disclosing the username/password in plaintext is good enough." And it sounds like you've got some kind of contract relationship with your customer. It's perfectly reasonable that you don't need to actually stop them from doing it, you just want to force them to make enough effort that it demonstrates bad faith on their part or something. This is obviously something you need to get legal advice on—otherwise, you're going to waste effort building something that's not sufficient to give you any legal protection, or waste even more effort building far more than you need for the legal protection you want. But let's assume you've got that legal advice, and now you want to proceed.


You can't give someone an encrypted password without also giving them the key. So the strength of the encryption is almost irrelevant. It will almost always be easier for them to recover the key than to crack the cipher—and even easier for them to just put a breakpoint on the mysqldb login function and capture the decrypted value on the fly. Which means you might as well use something dirt-cheap and dead-simple. For example:

def xor(text, key):
    infkey = itertools.chain.from_iterable(itertools.repeat(key))
    return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(text, infkey))

user = 'user'
encrypted_passwd = '\x1b\x04\x0a\x18\x12\x16\x19\x01'
key = 'key'

do_login(user, xor(encrypted_passwd, key))

Your lawyer might say that XOR encryption is not a sufficient "best effort" to protect your data, and you have to use, say, AES. If so, do it; it really doesn't matter.

Next, worry about hiding the key and the encrypted password (and maybe the xor function) somewhere in your code: rename them to something innocuous, embed them in the middle of other things, don't make it obvious that they're being used to create the password, etc.

You also might want to protect the interface to the MySQL login function. For example, if you wrap up the decryption code and the mysql_connect together in a simple Cython extension, they can't just break on mysqldb.connect or even _mysql.mysql_connect, which just means they need a C-level debugger instead of a Python-level debugger. You can even use a C or binary obfuscator around the decryption-and-connection code; there are a number of commercial products out there, and if your lawyer says you need to do this, you're better off using a well-known, state-of-the-art product instead of anything custom.


Meanwhile, if you're looking for technical protection rather than legal protection, you can usually gain a lot more benefit by mitigating the exposure rather than trying to avoid it, as dm03514's answer suggests: Restrict the client's access, so even if the user steals the client's credentials, they can only do the same things they could have already done with the client.

For example, let's say you want to prevent users from adding a new Shipping record without adding a corresponding Billing record with the correct links. You have logic in the client to verify that, but if they just grab the password from the client, they can add all the Shipping records they want.

Just move that logic to some middleware, so a single API call verifies and adds both records at once. Then give the client access to that middleware instead of directly to the database, and anyone who steals the client's credentials still can't add invalid Shipping records.

This won't prevent them from accessing you without the client, but, if done right, it will make it useless for them to do so.

abarnert
  • 354,177
  • 51
  • 601
  • 671
4

import base64

p = 'desired password'

y = base64.b64encode (p)

print y

and if you want to decode y:

z = base64.b64decode (y)

print z

Mason Snow
  • 41
  • 2
  • This is an easy way to make your password a code. This way you can code it then decode it when you would like. – Mason Snow May 31 '15 at 21:42
3

There are all sorts of things you can do to avoid this, a couple of which are:

  1. Package your data with your app, sqlite db file is easily packageable
  2. Expose your app logic through some sort of API and distribute a client, which uses the api to communicate with your app, so the client will never have to know any db credentials
  3. Create a mysql user account with correct permissions for your clients
dm03514
  • 54,664
  • 18
  • 108
  • 145
  • 1
    These don't _avoid_ the problem; you still need to store the credentials to connect to the API, or to the new user account, or whatever somewhere in the client. What they do is allow you to restrict the risk, so the user can only modify what you want to allow them to modify. What they don't do is prevent the user from modifying that stuff outside the client, which is what the OP was actually asking for. The former might actually be more important than the latter, and explaining why might make this the right answer. – abarnert Sep 13 '13 at 18:34
2

Strings are possibly the hardest thing to hide, no matter what you do to compile the executable with py2exe, or obfuscate it, etc. In practice, you cannot "hide" connection strings from the client. Of course, you could encrypt them, but then you'd need a means of decrypting them, and the client could easily (relatively) decrypt the username and password themselves.

Erik A. Brandstadmoen
  • 10,430
  • 2
  • 37
  • 55
  • He's not necessarily looking for "in practice", but for "sufficiently for contractual purposes". He explicitly says, "It does not need to be super safe, not disclosing the username/password in plaintext is good enough." – abarnert Sep 13 '13 at 19:13
  • That was added to the question after my answer... Anyway, "partially hiding" this is no solution at all. A malicious user with just a little tech skills will be able to extract these, and can mess up the database for anyone else.... – Erik A. Brandstadmoen Sep 13 '13 at 19:48
  • In the real world, "partially hiding" often _is_ a perfectly valid solution, usually for contractual or legal-standing or even financial/business reasons. But even purely for protection, it's not always useless. Half the shareware on Kagi was never cracked, because it was just hard enough that it was never worth someone's effort. There were billions of (sometimes paid) streaming views over different versions of Flash and Move before each version of each was cracked, which wouldn't have been true if they'd taken 2 hours to crack instead of 2 months. And so on. – abarnert Sep 13 '13 at 20:48
  • Also, that wasn't added after your answer. It was the last sentence of the original version; the [edit](http://stackoverflow.com/posts/18792537/revisions) just added the text starting "The client need to have Write permission…" – abarnert Sep 13 '13 at 20:50
  • I see your points, although I beg to differ. "partially hiding" is like closing all your doors without locking them, and hoping that no one will check whether they are locked or not. Well, EOD from my part :) – Erik A. Brandstadmoen Sep 16 '13 at 06:11
  • That's a good analogy. Closing your doors is measurably a little better than leaving them open, but not nearly as good as locking them, and even locking them is not perfect. If you have an theft insurance policy that will pay if your doors were closed, but not if they were open, making sure they're closed when you go out is worth doing. – abarnert Sep 16 '13 at 06:16
2

I think it would be better to set up an account for them on the database, and control access to the database using database rights.

Christopher Mahan
  • 7,621
  • 9
  • 53
  • 66