4

I'm trying to figure out a decent encryption strategy for a small business application. My main goal is to expose myself to as little unencrypted PI as possible.

I have no idea if I'm overthinking this and there's an easy way, so I thought I'd ask. I'd also like to hear if any of my thoughts are complete rubbish.

I've thought of 2 strategies thus far:

  1. When a user logs in, they're asked to input a master decryption password. This password is used to decrypt the private key and a random string is generated & stored in a cookie (or perhaps in local storage + transmitted with every post request). The private key is re-encrypted with the random string and whenever encrypted data is requested the cookie string is used to decrypt the key, then the data.

    • Disadvantage: As the server admin/hacker, I could obviously intercept the master password and decrypt the key, then the data.

    • Advantage: Pretty straight forward.

  2. The public key only is stored on the server. Between the server and the client is a reverse proxy which parses the content (similar to how ESI work). This proxy server would contain the private key and decrypt the data before serving to the client. The keys on this server wouldn't be managed by the same admin.

    • Disadvantage: As the proxy admin/hacker you could obviously intercept the data as it goes through. You would also have private key access.
    • Advantage: As the proxy admin/hacker you wouldn't have credentials to the application, thus you would only be able to sniff data that is requested by the end users.
    • Advantage: In a business environment, it's likely that this server can be much more easily protected against external sources. No incoming connections could be allowed at all.

The following are treated as a given:

  • All transport is secured by SSL.
  • In all scenarios I would have access to data as it was input. This could be mitigated by using JS public key encryption.
  • Actual application authentication is fit for purpose. I.E. Social engineering, brute force etc are all discounted. Browser-based issues/bugs are not discounted.
  • The encrypted data needs to be accessible by a team of authorised people.
  • It needs to be accessed through a browser.
  • The whole disk is encrypted at rest, which is no benefit to, say, breaching root via SSH.

I've discounted the following:

  • JS decryption—from what I've seen, this just means the private key is exposed to the end user.
  • Symmetric keys & pub/priv keys unencrypted on server, DB on another server. I'm not really sure of the value of these. As an Admin, or a hacker, I would have everything I need to decrypt the MySQL data if I were to breach the application server.
  • Third party Key servers: This just seems to pass the buck to someone else being able to see the content (though I am wondering if there's a multi-step process that could work in conjunction).
  • You have to assume a level of trust with your individuals. Think of a password manager for example; it uses a Master Password to encrypt all of your secret information passwords etc. If that master password goes 'walkies' then, in theory, anyone can access their account and view their passwords. In reality, though this is mitigated largely by the complex MFA that is in place, verifying who you are etc. – KingJohnno Nov 26 '17 at 8:12
  • Also: Think about the case of alternative decryption: When a user forgets their password - do you allow them to answer a series of questions to 'reset' their password or not? Personally, I would go down the MFA route, but thats just my opinion. – KingJohnno Nov 26 '17 at 8:14
  • Thanks for your note. I'm not sure i really follow. I'm talking about encrypting data and keeping the server admin from being able to access the unencrypted data. When i said "Actual application authentication is fit for purpose" that was supposed to cover off things like MFA. Obviously MFA doesn't help in terms of data being accessible to the admin (or a hacker with SSH access). – user164613 Nov 26 '17 at 23:50
2

The solutions you suggest can all be broken, given that they only move the trust somewhere else. You need a cryptographic solution that ensures the following:

  • Your server is able to accept and transmit encrypted material to the correct users.
  • The user has access to the encryption key.
  • The server has no access to the encryption key.

This requires in-browser JavaScript crypto, or a separate client-side program. Obviously, there is the possibility for a malicious admin to replace the JavaScript with a version that sends the key or original plaintext to the server, but this will always be a risk.

Depending on the type of data being stored, there is already a rather simple solution which is used by many paste websites like Zerobin and 0bin, as well as the popular Mega file host: client-side encryption. JavaScript in the browser creates a symmetric encryption key and appends it as the fragment (anything past the octothorpe) of the URL. The fragment is only visible to the browser, not the server. JavaScript in the browser encrypts data using this fragment and uploads the data to the server. The result is that you need the full URL in order to view the page, and the server is unable to decrypt.

A URL may thus be represented as example.com/path#fragment. Your ISP sees example.com, as this is what you send to the DNS server. Even with TLS being used, the domain is still sent in the clear as a result of SNI. /path is only visible to the server you are sending it to, assuming you are using TLS. This is what the server uses to determine what to send back to the client. The last part, #fragment, is only visible to your browser.

Take this example URL from Zerobin:

zerobin.net/?5cd884d7e1409f31#25LMCTnmrN3H/BPcebRjH6Gl05Sklj91CssV45YwQ/o=
|   host  |    identifier    |            base64 encoded key              |

In this example, the domain is, obviously, the address of the server. The identifier is the path which specifies what encrypted paste is being requested. When the page is retrieved, the fragment is never sent to the server. When fetching a file, all the server sees is this (in this example, using cURL rather than a web browser):

GET /?5cd884d7e1409f31 HTTP/1.1
Host: zerobin.net
User-Agent: curl/7.56.1
Accept: */*

This tells the server to retrieve the encrypted post and serve it, along with the JavaScript required to decrypt it. If the key is not correct, or the key is not present, the code on the page will be unable to decrypt it. This is intended to ensure that the plaintext is only visible to someone who has the URL. It is up to them to decide whether or not the URL should be distributed widely or kept relatively secret. This technique could be easily modified to use a password rather than a URL fragment, but if the issue is simply reducing PI, this should be plenty.

client-side encryption client-side decryption

More information about this specific information is on the Zerobin project page.

With sufficient engineering, this can be made to store far more than just text pastes. Mega for example supports accessing storage like a filesystem. There is even a utility which mounts your online user directory as a filesystem using FUSE, allowing interaction using generic filesystem actions, all the while ensuring the server does not know what is being accessed. Your application could be made to do this if this fits your requirements.

  • It looks like ZeroBin has been superceded by PrivateBin. – a CVn Nov 27 '17 at 12:28
  • Oh neat. It looks like it uses AES-GCM, which is great because Zerobin uses some really fucking weird setup used in some obscure JS function. Nice to have something a little more standard. – guest Nov 27 '17 at 12:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.