I'm a cryptography novice, but I think that the world needs to move towards an "encrypt everything" mentality as much as possible. As a result, I've been thinking a lot about ways to build a web app that stores all data on the server in a way that the server can't decrypt the data even if it wanted to.
Here's my thinking. I'd love feedback.
(Let me start by saying everything would be done over SSL. This isn't meant to protect the data over the wire, but to protect the data from the server.)
Server = any web server/technology, Client = a JavaScript web app
When a user signs up OR changes his/her password:
- Either an RSA key pair is provided by the customer (high security, less convenient) OR a key pair is generated by the server and sent to the client (customer has to trust that we won't store the private key, but more convenient)
- Also, a UUID is generated by the server and sent to the client
- The user enters their password into the client—this password is NEVER sent to the server
- The client uses PBKDF2 to generate a secret key
- This secret key is used to encrypt:
- The user's private key
- The UUID sent from the server
- The client then sends the following to the server:
- The public key
- The encrypted private key
- The original UUID
- The encrypted UUID
When a user logs in:
- The client sends the username to the server
- The server responds with the unencrypted UUID & a new UUID
- The client sends the following back to the server:
- The unencrypted UUID
- An encrypted copy of the UUID using the same method as above
- The unencrypted new UUID
- An encrypted copy of the new UUID
- If the encrypted copy matches the encrypted copy on the server, the user is considered authenticated, and the new unencrypted/encrypted UUID pair is stored for the next time this used needs to log in
- The server responds with an authentication token that is used for all further requests during this session, as well as the public key and encrypted private key
As the app is used
All data is encrypted using the public key before it's sent to the server, and decrypted using the private key in the client. If the server has to add content to the database, it's encrypted using the public key so that the server only has access to the data while it's generating it. Obviously this would not work in all use-cases, particularly highly relational data, but I think if the structure of the data is generally maintained, it wouldn't matter what the content was.
For example:
{
"username": "jsmith",
"name": "John Smith",
"message": "Hello there!"
}
Can be handled by the server very similarly to:
{
"username": "U2FsdGVkX1+B9f7mMjoU9sWnYU79eN2IiDxNsetNeUI=",
"name": "U2FsdGVkX188VmG67BS5lGDEs8NAUsQrG8eaVmyOlIg=",
"message": "U2FsdGVkX1+7cqObxGFq2ZR3rc05NznGdoPENDujAa4="
}
So maybe not all metadata could be encrypted, but it's definitely a step in the right direction.
I'd love feedback! Like I said, I'm a complete novice, so I could have made a terrible assumption somewhere in there, but it seems like it theoretically would work…
One final note: I recognize that JavaScript isn't ideal for encryption. That said, I think it's acceptable in this case because we're using JavaScript as an added layer on top of SSL & all other existing security best-practices.
"Let me start by saying everything would be done over SSL. This isn't meant to protect the data over the wire, but to protect the data from the server.)"
make no sense. SSL can't protect the data from the server. The server gets an unencrypted stream of data after the SSL decryption. $\endgroup$