8

I am building a PHP application that allows uploads of files (.doc/pdf etc) for review by a staff member. Some of these files will be somewhat confidential so I need to protect them.

Now the best solution would be to get the sender to encrypt these files with GPG or similar before uploading them and decrypt with a pre-shared key at the other end (on the staff computer, not on the web server).

However it is unrealistic to expect all of the customers to install and learn to use GPG in order to upload files.

So the best solution I can come up with is:

1) Do file uploads over HTTPS on a password protected page.

2) Encrypt files using asymmetric GPG and a public keyfile stored on the webserver.

3) Delete any unencrypted copies of the file in /tmp etc.

4) Send an email for staff notifying them that the file is available for download.

5) Staff member logs in and downloads file, server then deletes encrypted copy.

6) Staff member then decrypts file using their private key that is not stored on the webserver.

The idea here is that ever if the webserver is compromised (it is a dedicated server so not shared with others) the attacker will be unable to decrypt these files because they won't find the key there.

However: I think this is still vulnerable.

Because , if an attacker has root or even just control of the HTTP server user they will be able to read data from /tmp whilst the file is still being uploaded/encrypted and make an unencrypted copy which they can download later.

So perhaps I could do all of this in memory without writing to /tmp? But there is still a risk here that the attacker could discover memory addresses that the data is written to by uploading a file themselves and then use ptrace to inspect and copy those memory addresses.

I can't think of a way to fix this problem as I will need the data in plaintext in order to do the encryption. Is there a way in PHP to make the memory inspection harder? Or is there a third party web service that would be better to use for this?

user350325
  • 183
  • 1
  • 4
  • While this deals with security, I think you're lookgin more for a "how can I code this" answer, which is a better fit over at StackOverflow.com. It's security related, but there are areas where they overlap, and this seems to be one of them, and I think it's more of a coding solution than a security question as phrased. – David Stratton Jan 25 '13 at 21:57
  • Sort of, I know how to write the code to do this easily. I am more wondering about the general approach. – user350325 Jan 25 '13 at 22:03
  • Ah. Sorry, my mistake. I like how careful you're being! +1 for being thorought, and trying to think of everything. – David Stratton Jan 25 '13 at 22:36

2 Answers2

5

So perhaps I could do all of this in memory without writing to /tmp? But there is still a risk here that the attacker could discover memory addresses that the data is written to by uploading a file themselves and then use ptrace to inspect and copy those memory addresses.

A properly installed SELinux configuration can mitigate the risks of a compromised machine by control of the application. Ultimately, you have to keep the machine secure.

I can't think of a way to fix this problem as I will need the data in plaintext in order to do the encryption. Is there a way in PHP to make the memory inspection harder? Or is there a third party web service that would be better to use for this?

There's simply no way around the reality of having to have the incoming file in a cleartext state in memory at some point in the encryption process. Encrypting it in memory, however, is certainly the way to go.

Jeff Ferland
  • 38,170
  • 9
  • 94
  • 172
4

You can always use JavaScript at the browser frontend and encrypt it before ever hitting the network. You must still use TLS to transfer the webpage, in order to decrease the odds of a MITM attack that could change the Javascript code.

In the browser end, you could generate unique AES keys per-session and then encrypt the AES keys through OpenSSL with the staff member's key in the backend, so the recipient could decrypt the symmetric key with his own.

I may send you MEGA as a reference of a working example.

Benefits:

  • By using JavaScript you won't ever have the decyphered file in-memory.
  • By encrypting the AES key, you will have faster times.
  • You don't need GPG at the client side.
  • Keys are one-use, so they'd need to crack as many keys as there are documents.

Take care:

  • Keys have to be secured: they should not be written to permanent storage before passing them through OpenSSL encryption (and then forgotten).
  • At any attack sign, memory should be a priority. To mitigate stolen one-use AES keys, kill the webserver at the first sign, and restart it again. The user will only see a little downtime.
  • JavaScript transference and AES keys generation and transfer.
  • A browser extension can actually modify your JavaScript. Consider bundling the JavaScript as a browser extension for more control over that part.
ssice
  • 141
  • 3
  • Mega's implementation is interesting but not something I would realistically have time to build! I believe some problems were found with it's security anyway. I don't think I would need a one use key if I was doing asym encryption though. – user350325 Jan 25 '13 at 23:07
  • Sure. What I said is that you don't need assymmetric encryption for the whole file, and that you can use AES in the client. And there are ready-to-use libs available http://stackoverflow.com/q/793812/488191 – ssice Jan 25 '13 at 23:18