9

Background Information:

I'm part of a team of developers that runs a web application that stores and retrieves HIPAA (medical) data. Recently, the HIPAA guidelines were updated to include a policy that requires that all identifying client information be encrypted when it is "at rest" (stored in the database and not being accessed).

The Initial Problem

The first problem we had to tackle was determining the best way to two-way encrypt the data in a manner that makes the data secure in the event of a breach.

The initial Solution

The quickest solution we came up with was to use mcrypt to encrypt the data before we inserted it into the database.

The New Problem

The application we're developing is quite old (as web applications go) and uses a lot of procedural programming as well as heavy reliance on the mysql_query function to insert, update, retrieve, and delete data. We do not have the time or luxury of translating our code to a database-abstraction-layer. So, the only way to implement this encryption/decryption system is to manually edit all of the CRUD queries to use data that's been encrypted via mcrypt. This is very inefficient and extremely error-prone.

Our Proposed Solution

We decided that the fastest and most effective way to solve our problem is to overwrite the native mysql_query function with one of our own devising. In our new function, we would encrypt/decrypt the data values before sending the query to the server/ returning the resultset.

Where You Folks Come In

  1. Is this the best solution to solving our initial problem?
  2. How do you go about overwriting an existing, core PHP function?
Martin Thorsen Ranang
  • 2,241
  • 1
  • 30
  • 43
Levi Hackwith
  • 9,002
  • 15
  • 60
  • 111
  • So the problem is to encrypt data while it's been transferred to DB server? Or store it in an encrypted fashion? – Alex N. Jul 15 '10 at 20:52
  • To store it in an encrypted fashion and then easily retrieve, decrypt, and display it as necessary. – Levi Hackwith Jul 15 '10 at 20:55
  • I think you may be doing this at the wrong layer. Did you consider encrypting the entire MySQL database? Some solutions for this are discussed in [this question](http://stackoverflow.com/questions/143750/mysql-and-data-file-encryption). – Matthew Flaschen Jul 15 '10 at 20:55
  • @matthew: We did consider encrypting the entire DB but we're concerned about performance issues. Our intial solution is to encrypt ONLY the fields that are considered sensitive. That way, we can still run ad-hoc queries on the data via the command console. – Levi Hackwith Jul 15 '10 at 21:00
  • 1
    @Levi, some solutions will still let you use the console freely. E.g. while a TrueCrypt encrypted volume is mounted, any application can use the data transparently. Performance is an issue, but if most of the data is sensitive, I think encrypting the whole database is reasonable. – Matthew Flaschen Jul 15 '10 at 21:04
  • @Matthew, excellent info. Question: How do you mitigate the performance hit and is it possible to only encrypt a single table with TrueCrypt? Also, is it still true that there is no native encryption system currently in MySQL 5? – Levi Hackwith Jul 15 '10 at 21:08
  • It should be possible to have some tables encrypted but not others. What storage engine are you using (MyISAM, InnoDB, etc.)? There are [encryption functions](http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html) in MySQL, but I don't know of any built-in support for encrypting the whole database. – Matthew Flaschen Jul 15 '10 at 21:18
  • @Mathew, all of our tables are INNODB. – Levi Hackwith Jul 15 '10 at 21:24

6 Answers6

3

Although you've previously stated you can't/won't translate your code into a database abstraction layer, I believe that would be the ideal solution. Sure, it's a lot more work right now, but it pays off. What you've proposed is a hack, that can (and probably will) lead to errors and headaches in the future.

The next best thing would be to encrypt the whole database, as proposed in the comments. There are solutions out there for transparent encryption in different levels, ie: this or this

Another thing you might want to look into is MySQL's native encryption and decryption functions, which could be used to implement column-level encryption if you're concerned about performance.

quantumSoup
  • 23,443
  • 8
  • 38
  • 55
  • @Aircule Okay, that sort of solves one issue: Encrypting the data when it goes into the DB. We could use triggers to encrypt the data before inserting or updating. However, what about data retrieval? – Levi Hackwith Jul 15 '10 at 21:18
  • @Levi Can't you decrypt it upon retrieval ? – quantumSoup Jul 15 '10 at 21:21
  • @Aircule, yes we could but we'd have to call our decryption function manually before printing the data for every query and there are thousands of hard-coded queries. – Levi Hackwith Jul 15 '10 at 21:24
  • 1
    @Levi I think in your case a some sort of transparent encryption layer would be the easiest way to handle this. Refer to my edit above. – quantumSoup Jul 15 '10 at 21:27
  • Critotech also says it supports encrypting [only](http://www.critotech.com/products/product-features/) particular tables. – Matthew Flaschen Jul 15 '10 at 22:02
2

While the best solution would be the abstraction layer that the other answers have suggested, you can override existing PHP functions with your own versions with the PECL Runkit extension

Something like:

runkit_function_rename ( 'mysql_query', 'mysql_query_old' );
function mysql_query ( $query , $link_identifier=null ) {
   // modify $query here for UPDATE/DELETE statement and any WHERE clause, etc
   $newQuery = modifyQuery($query);

   if (is_null($link_identifier)) {
      $result = mysql_query_old ( $newQuery);
   } else {
      $result = mysql_query_old ( $newQuery, $link_identifier);
   }
   // modify $result here for returned data from any SELECT statement
   return modifyResult($result);
}

Note: By default, only userspace functions may be removed, renamed, or modified. In order to override internal functions, you must enable the runkit.internal_override setting in php.ini.

It's not a solution I'd really recommend. I had to do something similar some years back in java, where it was far easier to extend jdbc; but while parsing the syntax of SQL queries is hard enough, it gets harder still if your queries are using bind variables. Watch out for escaped strings! Watch out for any use of related function like mysql_db_query, just in case they're used alongside mysql_query within the application!

Apologies for shaky typing. My wife has been bouncing our router a few times while I'be been writing this suggestion

Mark Baker
  • 199,760
  • 28
  • 325
  • 373
1

I think one way of handling this automatically would be to look into MySQL proxy

and implement encryption through that. I played around with it 2 or so years ago when it was in a very early stages, and from what I remember it could basically intercept requests and do 'stuff' with them :) No code change required essentially. Hopefully this helps.

Alex N.
  • 12,095
  • 10
  • 43
  • 52
1

There are commercially available solutions to help with data at rest encryption. You can check out either Gazzang or Packet General. Both offer MySQL encryption to help with HIPPA compliance. Good Luck

CXMCoog
  • 41
  • 1
0

You could encrypt at the file system level, and let the OS handle it. If you wish to handle it at the PHP level, extend, don't overwrite.

function mysqle_query() {
  // Do some stuff
  // like replace fieldnames with AES_ENCRYPT(fieldname) on insert and delete
  // and replace fieldnames with AES_DECRYPT(fieldname) on select
  mysql_query();
}
Marcus Adams
  • 49,523
  • 8
  • 81
  • 132
0

I really think you are looking at this from the wrong perspective. This is not a problem to be solved by developers via encrypting/decrypting data as you store and retrieve it from the database - use an infrastructure solution.

Consider hardware or software whole disk encryption, encryption of the database itself via the RDBMS's transparent data encryption function (if the particular RDBMS has one), or via the OS.

See this document from NIST

ScottBai
  • 1,401
  • 1
  • 14
  • 15