1

I am to deliver a PHP application to my client, but I don't want to share the database credentials with him. I only want the database to be accessible via my application and by no other means possible. However, if I submit the PHP code, they can view the database credentials in database connectivity script and access the database from outside the script. How can I possibly stop them to have database username and password as their is no "compiled" code?

EDIT: The application and database are on two different servers.. i.e. app uses remote database connection, and runs on client's server database is on my own server.

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
  • 3
    You might want to limit the privilege of the account and bind it to localhost only. – iamsleepy May 04 '14 at 15:39
  • there is a correction.. the application and database are on two different servers.. i.e. app uses remote database connection, and runs on client's server database is on my own server. – Charchit Gupta May 04 '14 at 16:00
  • Then, bind the username only to client's server ? – iamsleepy May 04 '14 at 16:05
  • You could use environment variables ($_ENV), then set those on the server. They of course could still read those potentially, but it might be OK. Also limit the IP address that the connection can be made from on the DB. – Rich Bradshaw May 04 '14 at 16:05
  • Has the client access to the web server? – Gumbo May 04 '14 at 16:35
  • Refer this one http://stackoverflow.com/questions/97984/how-to-secure-database-passwords-in-php?rq=1 –  May 04 '14 at 16:37
  • 1
    One way or another you have to give the person access to the database. So what it the problem? Just ensure that the only access is what is expected – Ed Heal May 04 '14 at 16:40
  • 1
    “I am to deliver a PHP application to my client…” If the application must connect to your remote database server, then there is really no way for you to control who sees the database credentials since the application will have to access it remotely. – Giacomo1968 May 04 '14 at 16:41
  • simply use iframe and call the credentials from your own server. – Ansh May 04 '14 at 17:11
  • “simply use iframe and call the credentials from your own server.” How can you safely load credentials in from an IFRAME?!?! – Giacomo1968 May 04 '14 at 17:28
  • Let's step back a second. Why do you not want your client to have the credentials to a database used by their application? –  May 04 '14 at 18:11

2 Answers2

2

I don't want to share the database credentials with him.

If they have access to the client connecting to the DB, you have to. Otherwise, by definition, credentialed access would be impossible.

However you obfuscate the connection phase, once the connection is established anyone with access to the source code may hijack it however s/he desires. I don't think that even encrypting the whole modeling class would be enough.

This is particularly evident using the deprecated MySQL functions: once a connection is established, any other part of the code may issue a query and have it executed in the context of the connection, with no longer any need to know the credentials. But unless you do things very carefully (and, I suspect, depending on the attacker's ability, even if you do), the same will hold true with mysqli, PDO, and so on.

What you can do is:

  • limit privileges on the database to the barest possible minimum. This should always be done, BTW, because you never know what vulnerabilities might be in some code, yours or somebody else's that's connected to yours (libraries, plugins, ...), and who could thence gain access to the application.

  • limit connection IP to that of the client. Another thing you should always do whenever practical: there's no reason not to.

  • move whatever is possible to move into stored procedures and functions.

If you want (and really need) even more control, you need more work:

  • instead of using prepared statements (and, BTW, you will now have to have "static" statements - you won't be able to prepare, say, SELECT {$field} FROM table WHERE id = ? and bind it to id), move the statements themselves to a thin layer on the database server, passing parameters via (e.g.) JSON.

So what was, say,

SQLExec("SELECT * FROM users WHERE userid = ?", "1")

can become very easily

HTTPExec("SELECT * FROM users WHERE userid = ?", 1);

but now, on the server (you'll need a HTTP server there), a script will verify that the requested query is indeed among the approved queries; and only if so, execute it and return the results. Depending on several factors, you might even be able to pass this as a "performance improvement". On the other hand, the "database" server is now more loaded.

Now the client cannot issue a "DROP TABLE Students;" statement, because this statement is not among the approved statement list.

To generate the approved statement list, you can instruct the server to approve everything and store the queries it receives; you then do an exhaustive review of all the web app, in order to trigger all queries at least once (you probably have a test integration script that already does this, and verifies that results are OK); when you've finished, all the queries just received, and only those, will be considered "valid".

Someone changes a comma in one of the queries in the client code -- and the server will reject the query as unauthorized.

This is in the end equivalent to moving (or duplicating) the relevant application code onto your server, so there might be issues: in effect, you're no longer giving your client the full application.

(At that point you could even replace all the queries in the client code with their, say, MD5 hash. The server does not really execute the SQL sent by the client anyway, it executes the good copy that's present server side for comparison purposes. So sending the query or its MD5 signature is perfectly equivalent).

LSerni
  • 55,617
  • 10
  • 65
  • 107
  • 1
    Prepared procedures? I guess you’re mixing up prepared statements and stored procedures. – Gumbo May 04 '14 at 19:53
  • So how would you implement such statement verification? – Gumbo May 05 '14 at 04:49
  • Just as I said - I'd simply check, server side, whether the query requested is one of the "known" ones. This can't and won't defend against all possible attacks, but it does restrict what the client can do. Of course much depends on *what* queries are to be made available; if the application has to be able to do almost everything on the database, there's little to be gained in vetting that 'almost everything'. And if you need no fancy stuff and the desired limits can be enforced through permissions only, then this option is needless. – LSerni May 05 '14 at 06:32
  • You *simply* check. I think stored procedures would be a more reliable solution. – Gumbo May 05 '14 at 06:50
0

You could ioncube the config file that you store the database connection information in. You can upload single files for free.

http://www.ioncube.com/online_encoder.php

xaoseric
  • 33
  • 1
  • 7
  • This isn't an effective protection. Even if the file is encrypted, you can still (necessarily!) `require("config.php")`, then echo out the variables. –  May 04 '14 at 18:10
  • @duskwuff You can test for free with archives of many files if you want. Better would be to make such data available via function calls with misleading names and behaviour that does something different unless called in a special way (e.g. have get_date() return the date unless called with a 'secret' value and then return a password). There are features in ionCube such as include attack protection to prevent dumping of variables, and other ways to store data such as with file properties, but these are not available in the online Encoder. Disclosure: I am associated with ionCube. – Nick May 05 '14 at 08:09