Verifying data that is encrypted in the browser - javascript

We have a file upload system that PGP encrypts data in the browser before it is sent to our servers. The files are then viewed by us in a specially designed local program. We decided this was the safest way to store that data. One downside to this we find in our own testing is that we can really upload anything at all, random strings etc., because we can't verify what that data is once encrypted without keeping our private keys on a server that is connected to the internet. It seems to me that this is a pretty big potential flaw, though I can't put my finger on exactly what could be done with it. Aside from sanitizing and checking data before viewing it, what can we do to mitigate the issue? Should we take another route entirely for protecting the data?
Edit: We realized the public key used to encrypt could simply be changed by an attacker and they'd have access to all files encrypted from that point. The current suggestion is to encrypt using hashed user password+salt generated at login time and then storing that key on another server (protected by master password) so that we too can view them. The issue of changing keys seems to be mitigated by this (though keys could plausibly be intercepted while being sent to the secure storage server).

Related

Secure storage of client-side keys

I am building a front end for an existing API that uses Ethereum private keys to sign data. This works completely fine for other applications sending data to the API, however I cannot find a secure way to persist private keys in the browser. I am questioning to use LocalStorage since the front end will be in Angular and it handles XSS well. however, most post suggest against placing anything secure in LocalStorage.
Its worth noting that these keys are generated client side and never exposed to the server and it does not matter if the client alters or deletes them.
LastPass utilizes a user entered password to decrypt local keys, I am not opposed to implementing this, however I would prefer the user to not enter a password and rely only on secure storage of the keys.
Any advice is greatly appreciated.

How do i persistently and securely store a users third party api keys?

I'm working on a Node.js app which requires the user to enter his API keys from a third party service (the service doesn't allow logging in via oauth).
Right now i'm storing these in a .env file, so it needs to be entered on setup.
I'd like te user to be able to set the keys once in the user interface (with a password) and then store them persistenly, so that when quitting the app and restarting again, the keys will still be there. How would i go about this? Do i encrypt the keys and store them in a db? Are there any other methods?
In general this is too much risk both for your users and you as the service provider. If these are valuable api keys that you want to store, your service becomes a good target. As you also noted, this is what oauth was invented for.
If you still decide to do this, you can trade some ux for more security. You should definitely encrypt api keys, but where to store the encryption keys so that it actually makes sense is always the question.
Think about how an attacker might get hold of these api keys (the threats), and that will help come up with adequate protections (mitigations to those threats).
For example, an attacker might access the database directly or offline, like from a backup, or through a compromised db server. For this, standard encryption at rest as provided by your dbms is good, especially if you use something like AWS and KMS to store the encryption keys. So you need encryption at rest, but that's not enough.
An attacker might compromise your app too, so transparent encryption doesn't help. You can for example encrypt your sensitive fields (ie. the api keys) on the app level, with unique keys associated with each user, stored securely in an appropriate service (like a HSM, or in something like Secrets Manager in AWS). This might still allow access to an attacker, but it's getting more difficult, and you get a lot more control and auditability over key access.
And to take it one step further, you cab derive keys from your users passwords with a proper key derivation function (like pbkdf2 or similar), and never store them in a database, only memory. This means logged in users' secrets might still be compromised by an attacker if they have access to server memory and/or network communications on the server's end (after tls is terminated), but secrets of offline users will still be secure, because even you don't have the key to decrypt them. This of course only works if you only need access to their api keys as long as they're present.

Is it possible to sign/encrypt data on the client-side to ensure it was not manipulated by the user?

I save information in local storage and I want to make sure the user didn't replace the data or had fun with it.
The client receive an object, javascript analyse it, do it's thing and store some of it in the browser's local storage.
The data is sent to the server every 30 seconds and the server replies by another object, based on the previous data sent.
The process happens often so it would be preferable to avoid sending the server tons of data and make heavy query to verify the integrity.
I know Javascript in the client is prone to debugging, reverse engineering etc. But it would definitely add a layer of security so at least some people wouldn't bother. (Security through obscurity)
My initial thought was to make a checksum of the value I want to store, send it to the server and compare it to the checksum stored. If the result mismatch, dismiss the data on the client-side. I think it would be preferable to avoid storing in database and be able to check if it's legit with some function.
I would prefer if the data stored would look like a token (like a signed or encrypted base64 string) rather than raw data as it would leak some information about how the code works and may make it vulnerable.
Is there libraries or method of doing so that could help me in my journey?
Is it possible to sign/encrypt data on the client-side to ensure it was not manipulated by the user?
Short aswer - No, it is not possible.
Long answer - Any message authentication code (signature, hmac, ..) requires a secret value. As soons as you do the signing on the client side throuhg JavaScript, there is no way you can prevent the user to access the secret or modify data.
Take in account the user even may modify the application to change the client-side validation. Long story short - never trust user's input, you have to always validate data on the server side.
Suggestion - you may send the data to a server service and the server could sign/hmac the data. The same way you could validate the data integrity.
But it would definitely add a layer of security so at least some people wouldn't bother. (Security through obscurity)
In my opinion - it doesn't matter much. If the user doesn't care, he won't modify the data. If you have a dedicted user, no level of obfuscation will stop him.
I would prefer if the data stored would look like a token (like a signed or encrypted base64 string)
Nothing prevents you to do so.

How does one protect an AES password that is used on the client?

I want to use Stanford's implementation of AES here:
http://crypto.stanford.edu/sjcl/
However, it is essentially useless if I use it as they suggest
SJCL is easy to use: simply run sjcl.encrypt("password", "data") to
encrypt data, or sjcl.decrypt("password", "encrypted-data").
As anyone can simply load my site, look at the java script and use the password to decrypt the data the same way I would.
How do i make this solution useful?
With a bit more back-and-forth I think I understand what you want to know better enough to give you an answer. Let me know if this is what you were looking for.
In general, managing symmetric keys is very difficult. There are two primary uses for symmetric ciphers:
Protecting the privacy of stored data for later use by the same person. If you use an online backup service, you really hope that your data is encrypted on the client before being uploaded to the online service -- you do not want them to have access to your data in plaintext. But when you go to decrypt the data in the future, you're the one to supply the key. This means you could store the key on offline media (CD-R, USB memory stick, SD card, little notebook next to the monitor...) or online (browser cookie, OS-supplied keychain of some sort, or standard file...).
Protecting the privacy of data while in transit between two parties. One party encrypts the data and the other party decrypts the data. This is how spies communicate, how TLS provides HTTPS client-to-server security, how SSH provides client-to-server security. In this case, both parties need to agree to the key that will be used, and this can be done with Diffie-Hellman-Merkle Key Exchange or using a public-key encryption algorithm such as RSA to allow one party to encrypt a randomly-generated session key in a way that it can only be decrypted by the other party.
The library you have found looks like it is highly optimized for the first case -- allowing users to encrypt their data for you to store and then retrieve for them later. Because they use a password based key derivation function it is prepared to handle the poor passwords that are available through simply typing on a keyboard -- the function will allow building safer keys out of just what a human can (or will) type on a keyboard.
Of course, it could be used for the second case, but presumably you're using this in a browser that has full TLS support, which can provide for end-to-end security in case you choose to use both client certificates and server certificates.
If you chose to allow the user to store encrypted data through your software, you should definitely make clear where the decryption key is being stored. I could see a use case for having a cookie on the browser store the key -- so that the user does not need to re-type it when they want their data. But if they change machines or browsers, they'll need to know the password so they can again retrieve their data.
However, if a user thinks their data is "secure", perhaps they should re-type their key every time they want to use their data. That way, the user alone is responsible for the security of the key; browser flaws that allow exposure of cookie data -- or locally-running malicious code -- cannot simply read the key off disk.
The downside of all this, of course, is that there isn't an easy answer available: you have to decide between the simplicity of storing passwords or the safety of not storing passwords.

Is there a way to securely send information in Ajax?

I'm currently developing an application in HTML+JS based almost entirely in ajax connections (using the jQuery.ajax() call to ease the process).
I was thinking about the best practice to make secure calls without using HTTPS (at least at this time. I can't afford paying for a certificate right now).
At this point, the only thing that concerns me is the registration and login steps. Maybe the login is a bit easier. I thought of sending the username and a timestamp, and then encrypt them using the user's password. So, by doing this, I wouldn't be sending any password (keeping as a secret like in OAuth). The server should check the user, decrypt using the password and pairing the recieved timestamp with the decrypted result. The server should keep the nonce-like number into a database (to avoid repetition attacks) and then give back to the user another unique id (encrypted with the user's password). At that point the user should start using that key to encrypt all his information (and probably another nonce) and send it to the server. Please correct me if you find any mistake or leak.
The very big problem to me is the registration. I can't encrypt with a regular password the information, because if I do that in the javascript, any could know the password. If I serve temporary generated passwords to encrypt and I send it from the server to the client, any sniffer could get it and use to decrypt the info.
I know HTTPS could save my life at this point (and maybe that's the only solution), but at this point I'm not able to use it.
Is there any other solution, or should I wait until I can use HTTPS? Bear in mind that if I could skip the wait, it would be better. Thanks mates!
Short answer: You can't do it without HTTPS
Longer answer: If you try to do it without HTTPS, you will find yourself trying to reproduce everything that HTTPS was designed to do. You could reach at some point, but it is unrealistic to believe that you will succeed in implementing even the 1% that HTTPS offers. The only benefit you will have would be an obscure security mechanism (security through obscurity), which may be OK for not critical systems, but would fail miserably in a real critical situation.
You could create your own certificate you know and then work with Ajax the same way as with regular HTTP calls. The only drawback is that the users will get a warning message.
Using an SSL Certificate is the only way really, if you encrypt it in javascript anyone can read the code and decrypt it.
http://www.startssl.com/
Generate a public/private key pair on the server, along with a randomly-generated salt.
Attach the key pair and salt to the user session object.
Send the public key and the salt to the client-side code.
Use the public key and salt to encrypt the AJAX requests.
This would not be a trivial task. You'll probably find that it's cheaper and more effective to just buy a certificate.
EDIT: This also means that all the regular HTTP traffic (HTML, images, CSS, etc) is sent in the clear. That could be a problem, since it might allow an eavesdropper to indirectly figure out what the user is doing.
I think you should have a look at :
http://assl.sullof.com/assl/
Here is the description of the project :
aSSL is a library distributed under MIT License thats implements a technology similar to SSL without HTTPS.
aSSL enables the client to negotiate a secret random 128-bit key with the server using the RSA algorithm. Once the connection has been established, the data will be sent and received using AES algorithm.
aSSL is composed of some Javascript files and a server side component. Because I have recently changed the negotiation algoritm from RC4 to RSA, only a pure Javascript (ASP) server component is currently available. I will do a porting for the main web languages (PHP, Java, Perl, Python, TKL, etc.) as soon as possible once the library has passed the beta phase.

Categories