When I've done this I've moved the encryption away from the web server altogether. Basically I've had the following scenario
- A database server which stores the
- A web server which
runs the application and
stores/retrieves encrypted data
- A crypto server which performs the
encryption and decryption and which
is locked down
Basically the web server calls a web service on the crypto server, which is only available on an internal network and says "Here's some data, and the type of the data". The crypto server makes a decision on key size, key expiry etc. based on the type of the data, encrypts it with a new symmetric key and salt and passes back a binary blob plus a key identifier. The crypto server then stores the key in it's own SQL database, but protects it with an X509 cert first, which only the crypto service has access to - so if you manage to access the database remotely it's useless as you'd still need OS access to get the X509 cert to decrypt the keys, and in any case the data is held elsewhere.
The crypto server admin passwords are held in a the "break box" where it takes two separate people to combine their parts to get the password.
This means developers don't have to worry about what algorithms to use, or secure key storage as it's taken care of by the crypto server, and you can update the algorithms used as your process changes or new rules come out without having to update anything other than the crypto server. Only the process running the web application can call the crypto server, normal user accounts, or even administrator accounts cannot. Database administrators who can see the web database only see encrypted data and cannot access the keys either.
Even if the web server is compromised it's still limited in what it can do, call the crypto server to get keys, and then call the data storage database to get the data the keys refer to. Hard to do if the compromise is just the ability to run arbitrary code, without knowing how these things happen or where the servers lie on the internal network.
Of course if the compromise is a rooting, and the attacker can grab your code and impersonate processes, well all bets are off - but that's always going to be the case.