6

I want to save some user-generated data with some signature of the user that generated it (let's say that the user has to fill some forms with some data and I want him to sign the written data).

The server side is some random server language (that has big enough libraries to cover everything I'll need to do), the client side is Javascript (and the webapp is a SPA, Single Page Application). The client machine can be a cellular (a fairly new smartphone... but still a slow CPU compared to standard desktops/laptops)

The DB backend is "insecure". It is possible to tamper the data (many persons have access to the machine, perhaps it's "in the cloud"), but there is and a strong sequential continuous backup where it is very difficult to tamper with the already written data (something similar to a secured sequential log) (perhaps a digest of the log is shipped continuously to a secure server, or the sequential log is kept in another cloud totally separate from the first one, or if it only has to save some hashes, even a random machine can do it).

What I want to be able to do is make very difficult for third parties that have read/write access to the DB machine and read access to the server machine to add/modify records created by the user. For the deletion I'll do this: the program doesn't do any real update/delete operation. Every update/delete simply add a new version of the data and marks the old as "old". The hash of all the data is continuously saved on the tamper proof backup. This will even protect me from updates to old data. The only thing it won't protect me is against adding new data through spoofing an existing user.

I will use https to secure transmission (with certificates bought from some SSL cert authority).

I know I can't really secure the site (as in "the javascripts that will go to the user"), so that this is a weak point (someone could install a keylogger directly in the javascript code). I've watched around but it doesn't seem possible to sign some javascript code, send it to a client and let the client check the signature (probably because the javascript, being a dynamic language, would let a malicious javascript inject himself in the signed code/in a random piece of the javascript base library, so it would be very difficult to firewall everything the pre-existing environment). I could check the signature from the server side (the server program is signed and sends only javascripts that are signed).

I don't want to use client-side SSL certificates because they are difficult to use for the user (if the user changes computer he has to reinstall the certificate, if the user forgets he has a certificate in a computer it's possible to steal it...)

The solution I thought was to use ECDsa, generate a public/private keypair from the user password (plus some other data) and then the client signs the user's data client-side. The public/private key generation happens client side. When the user is created and the password is chosen, the client generates the public/private keypair and tells the server the generated public key. The user only needs to remember its password.

Clearly the weak point of this is that someone could add a new public key of the user on the server and sign something with the new public key, but it would be quite easy to spot this, because there would be a new public key. Something more clever would be to change an old public key and then resign everything the user signed with that new key, so it would be impossible to show if the data was tampered, but for this there is the tamper-proof log.

Another weak point would be from the user side: someone could install a keylogger and steal the password, but this is a problem of all the "standard" password schemes (for this I'll add a TOTP authentication, see at the end)

Password recovery would be handled "manually" (a super-user would have to confirm the identity of the user and then sign the change of the password with the super-user's key)

Now let's make it a little more complex: the private key is generated from the PBKDF2 of a salt unique for each user (sent by the server) plus the user's password. Sadly to make the software compatible with cell phones I will need to keep the iterations of PBKDF2 low (mmmh... On my old Optimus W, 1000 iterations require 8 seconds, while with the S3 it's nearly instantaneous... But 1000 iterations isn't very strong) (perhaps I could use Scrypt instead of PBKDF2... It should be more resistant to GPU attacks)

So in the end it would be:

User inserts username and password and press a button. The client asks the server for the salt, for the number of iterations of the hashing function and for the time of the day (this to stop attacks based on reusing the same signature), then calculates the hash of the password by using PBKDF2/Scrypt, regenerates the ECC private key, signs the message (that contains the operation requested and the time of the day received by the server) and sends the signature. The server must remember what challenges he has given and what have been replied (and so are "exhausted").

After this I could add a two step verification (using the algorithm used by Google Authenticator, for example). The key of this would be shared between user and server. The one-time password could be inserted in the various messages signed by the client. The server could save the calculated time of the TOTP so that it would be easy to verify at a later time.

So the question is: is everything ok? Is there a pre-made solution that does everything? Is there an hole in my reasoning?

  • So you want users to sign forms that will be stored in an insecure database so the images of their signatures can be stolen and used for fraudulent activities. Wow. Even identity thieves are now using stackexchange. Unless by signature you mean something else. I can't make heads or tails out of your question. There's a lot about how insecure your solution is intended to be, and absolutely nothing about what your system even is. Does the system exist for no other reason that to be an insecure system to looks secure to the user by sounding all secure with signatures and other buzzwords that soun – user91239 May 16 '13 at 19:44
  • Why don't you trust your own server, nor your own DB? Why do so many people have access to the DB, can't you just limit the nr of admins? Why do you think someone could tamper the JS code, when serving it via SSL/TLS? And why do you think it is a good idea to share the key with the server, if you think it can't be trusted? – Andy Aug 12 '16 at 16:27
4

The DB backend is "insecure". It is possible to tamper the data (many persons have access to the machine, perhaps it's "in the cloud") [...]

What I want to be able to do is make very difficult for third parties that have read/write access to the DB machine [...]

Your goal shouldn't be to make it very difficult for third parties to modify the data from your database. Your goal should be to prevent anyone but the administrators to access both the server and the database.

What you are doing right now is like giving your bank account number and password to complete strangers and then ask how you make it difficult for those strangers to take your money. Well, you might think of not sharing the account information in the first place.

It's also unclear what “in the cloud” has to do with security. Most cloud providers such as Amazon or Microsoft do a great job of hosting virtual machines in a very secure manner.

Therefore:

  • Get rid of those “third parties” who can SSH your server with su access. This is the wrong way of hosting web applications. Don't do that. And if you do, please, inform your users on the website that all personal information they give you can and will be shared with complete strangers.

  • Use TLS. There are no reasons not to use one, especially since free services exist.

  • Don't trust client-side. No, you can't sign JavaScript, and in general, on client-side, you can't protect your users neither from themselves, nor from any crap they install on their machines. Viruses would be able to inject themselves into a browser and modify JavaScript; if you do a mechanism which checks if JavaScript is tampered, they would be able to tamper the checking mechanism itself.

  • While you can encrypt information on client-side, there are few good reasons limited to few cases where you would actually do it. The reason is that, once again, client machine shouldn't be trusted, because it's usually difficult for a user to secure his device. The server, on the other hand, can be secured very easily, and with TLS, man in the middle attacks could effectively be prevented.

Thus, ensure both your servers and the communication between the servers and the clients are secure.

A few notes:

Sadly to make the software compatible with cell phones I will need to keep the iterations of PBKDF2 low [...] (perhaps I could use Scrypt instead of PBKDF2... It should be more resistant to GPU attacks)

This is why you need to compute the hash on the server. If you reduce the number of iterations, you're making it easier for the attacker to bruteforce the hashes.

Searching for a different algorithm is a wrong solution here. Remember that an attacker will have powerful CPUs and GPUs. Your goal is to slow an attacker, and you do that by increasing the iterations.

After this I could add a two step verification (using the algorithm used by Google Authenticator, for example). The key of this would be shared between user and server.

Which means that your “third parties” will have full access to those keys. In this context, two-step verification makes things much worse: it gives you a sense of security, while providing absolutely no benefit.

0

Since there is no answer, I'll be bold and propose one, even though I don't completely understand your constraints.

First, your question contains a mistake. It is not necessary to "buy" a security certificate. StartSSL (offered by StartCom) is free, and Let's Encrypt (https://letsencrypt.org) is free. There are others, too.

But if you don't want to use TLS or other certificate-based asymmetric encryption technology to provide your specific form of security, why not do symmetric encryption/decryption using a shared secret?

To share a secret, use the Diffie-Hellman algorithm (but lookup ways to protect against Man-In-The-Middle attacks). An implementation in JS and PHP (TightConnect in github) is available as a demo (http://www.springtimesoftware.com/tightconnect/demo/).

  • 1
    There is no excuse for not using TLS (SSL). If you don't encrypt connections to your web site, users will inevitably be targeted, lose trust in your service, and potentially sue your company for negligence. I have not heard of a web framework that doesn't support TLS. Use it, even if you don't want to. – Chris Cirefice Aug 12 '16 at 4:09
  • I agree with your comments. TLS does it right, and you don't want bugs to compromise security. The Let's Encrypt project is bringing free and universal TLS to the Web. Note that current TLS implementations are actually faster than non-encrypted connections. – David Spector Aug 13 '16 at 10:23
  • What happens when someone begins tampering with the actual Javascript/HTML? How does TLS help you there? – Robert Harvey Oct 11 '16 at 1:35

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.