views:

55

answers:

2

I have a written a Python module which due to its specifics needs to have a MySQL database connection. Right now, details of this connection (host, database, username and password to connect with) are stored in /etc/mymodule.conf in plaintext, which is obviously not a good idea.

Supposedly, the /etc/mymodule.conf file is edited by the root user after the module is installed, since the module and its database may be used by all users of a Unix system.

How should I securely store the password instead?

+4  A: 

Your constraints set a very difficult problem: every user on the system must be able to access that password (since that's the only way for users to access that database)... yet they must not (except when running that script, and presumably only when running it without e.g. a python -i session that would let them set a breakpoint just before the connect call and look all through memory, so definitely able to look at the password).

You could write a daemon process that runs as root (so can read mymodule.conf, which you'd make readable only by root) and accepts requests, somehow validates that the request comes from a "good" process (one that's running the exact module in question and not interactive), and only then supplies the password. That's fragile, mostly because of the need to determine whether a process may or may not have a breakpoint set at the crucial point of execution.

Alternatively, you could further raise the technological stakes by having the daemon return, not the password, but rather the open socket ready to be wrapped in a DB-API compliant wrapper; some Unix systems allow open file descriptors to be sent between unrelated processes (a prereq for this approach) -- and of course you'd have to substantially rework the MySQL-based DB API to allow opening a connection around an already-open socket rather than a freshly made one. Note that a validated requesting process that happens to be interactive would still be able to get the connection object, once built, and send totally arbitrary requests -- they wouldn't be able to see the password, technically, but that's not much consolation. So it's unlikely that the large effort required here is warranted.

So the next possible architecture is to mediate all db interaction via the validating daemon: a process would "log into" the daemon, get validated, and, if all's OK, gain a proxy connection to (e.g.) an XMLRPC server exposing the DB connection and functionality (the daemon would probably fork each such proxy process, right after reading the password from the root-only-readable file, and drop privileges immediately, just on general security ground).

The plus wrt the previous alternative, in addition to probably easier implementation, is that the proxy would also get a look at every SQL request that's about to be sent to the MySQL db, and be able to validate and censor those requests as well (presumably on a default-deny basis, again for general security principles), thus seriously limiting the amount of damage a "rogue" client process (running interactively with a debugger) can do... one hopes;-).

Yes, no easy solutions here -- but then, the problem your constraints pose is so far from easy that it borders on a self-contradictory impossibility;-). BTW, the problem's not particularly Python-related, it's essentially about choosing a secure architecture that comes close to "squaring the circle"-hard contradictory constraints on access permissions!-)

Alex Martelli
Thanks Alex, your detailed answer was helpful and instructive beyond my imagination :)
David Parunakian
@David, you're welcome!
Alex Martelli
+1  A: 

Dear David,

Why not create a default MySQL user account with restricted permissions? You could set it up so it can only read the particular database. You could also restrict the default user to only being able to SELECT, with no ability to INSERT,UPDATE or DELETE. The particular privileges you should set of course depend on your situation.

The syntax for restricting/granting privileges is covered here: http://dev.mysql.com/doc/refman/5.1/en/grant.html

By creating a default, restricted MySQL user, you could perhaps put the password in a plain text file with no harm done.

Meanwhile, if you add user and password as optional parameters to your module's connection function, then more privileged users could supply their own password to be able to interact with the database with greater privileges.

Of course, this just amounts to questioning the original premise of your post. If that direction is not viable, feel free to ignore! :)

Regards, unutbu

unutbu