Is it possible to create a login process that require开发者_StackOverflow中文版s a public/private key through a web browser? The public key would be stored on the server and the private key would be kept (and encrypted) by the user.
I basically want to do something similar to what SSH does, but through the web. Perhaps a custom method of HTTP Authentication (other than "Digest").
I know that it may not be possible to do this with a stock browser, so extensions to make this work are acceptable (Chrome/Firefox).
The keys would ideally be encrypted on a USB Stick. When the USB stick is unplugged in has to be impossible to login (don't want the browser to cache it).
This would be used internally.
Edit: Client certificates would be what I'm looking for, but how do I store these certificates on a USB stick? Also, is there information on how to authenticate a user using PHP?
This is Client authentication via certificates.
Your server should be configured to require a client certificate and also be configured with a truststore.
All the browsers support this.
You just have to import the client keystore having the private key and certificate to the machines set of certificates.
For windows it is in internet options
I doubt you'll be able to do this with a web application. The browser is sandboxed from the operating system and you would be unable to have the web application detect the presence of a USB drive nor would you be able to read any data off of it with the web application. So you would need the browser to do that for you, and they are not designed to work that way.
When you load a client cert into the browser it gets loaded into certificate storage. Those are different depending on browser and OS. On OSX they go into KeyChain. On Windows some will go into the OS key store and some will go into the browsers own keystore (Firefox I believe works this way). But none of them will allow you to define an external keystore and then encrypt and decrypt the key you're trying to protect as it reads and writes from that drive.
What you are doing would only be possible if you wrote your own desktop application (essentially your own browser) that did this for you.
It is possible you could do it with an Adobe AIR application. Adobe AIR supports reading and writing from a USB drive, it supports encrypted databases (128-bit AES/CBC crypto with SQLite) where you could store the data you are trying to protect, and it's cross-platform.
With any of these solutions you will likely be stopped at the requirement of need to ensure the USB key is plugged in. That is likely tough to do. How would you stop the user from simply copying the files from the USB key to the hard disk and then using the key from there so that they did not need to use the USB key?
To get to that level of control you may need to look at a truly native solution. C++, Objective-C, or Java. Java is going to be the only one that offers you a cross-platform solution.
If the USB key is a convenience to the end user as opposed to a requirement, then Adobe AIR would be a solid solution. If not, then it's time to brush up on your desktop software development skills.
Here is how I did web based login using RSA public/private key in php:
- On registration, server saves user's public key and gives user an ID
- On login, user is asked to enter his ID and private key
Registration is very simple.
But login is done in this way:
- Server generates a string that contains some data: random string, current time, user's ip
- That string is encrypted twice with AES with two passwords:
nonce1 = pass2( pass1( string ) )
- Same string is encrypted again with AES with two passwords, but in reverse order:
nonce2 = pass1( pass2( string ) )
and the result is encrypted with user's public key:nonce2encrypted = encryptPubKeyRSA( userPubKey, nonce2 )
P.S. The string is encrypted with two passwords, to be harder to make a brute force attack.
The login form contains three hidden inputs: nonce1
, nonce2encrypted
, and nonce2
without value.
Then the user is asked to enter his private key in a textarea that is outside <form>
tag (to be sure that it will not be sent to the server on form submit), a javascript will decrypt nonce2encrypted
and set decrypted value to nonce2
. Then the textarea with private key is removed from html with javascript, just to be sure it will not be stored somewhere in the browser or sent to the server.
The server receives nonce1
and nonce2
, and decrypts them with that two passwords. If the decrypted values are the same, the user receives a cookie and is logged in.
P.S. That cookie also contains some encrypted data, for example user ip. This does not allow somebody that stole this cookie to login from another ip.
You can view this method in action (project on github)
Client certificates are the answer. Most/All browsers import these client certificates as PKCS#12 (.p12, .pfk).
You can convert an existing x509 certificate to a PKCS#12 file with the public key (.crt), private key (.key) and CA certificate (.crt). You can do this with OpenSSL using the following command:
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile ca.crt
If you self-sign your certificates it's important to make sure the certificate serial is different than other certificates. If they are the same you can experience errors trying to import the .p12 file (So watch out for -set_serial in openssl examples).
Unfortunately the only cross-platform way to make certificates mobile/removable is to use a smart card (using PKCS#11).
On Mac OS X Safari and Chrome access their certificates from the keychain. You can actually create a custom keychain on a USB flash drive (File -> New Keychain). After you've created the keychain you can simply drag your .p12 file into your Keychain. What's nice about this is you can control access to what application has access to the certificates, and you can have the keychain itself lock after a certain amount of inactivity.
With Safari this works beautifully. If you unplug the flash drive it stops sending that certificate after a couple seconds. If you plug it back in, it picks it up immediately. If you lock the certificate with "Keychain Access" it asks for the password. It prevents you from properly ejecting the flash drive while in use, but after a minute Safari releases its lock.
Chrome is finicky. It caches the certificate for several minutes. If you lock the keychain, it continues to use the cached version. If you try to properly unmount the flash drive it will tell you Chrome is using it until you close it. If you plug the flash drive in while Chrome is running it won't pick it up.
So it appears that Safari is the only browser to support this. Firefox and Opera both have their own key-stores.
If you want to hide your custom keychain on the flash drive you can create an invisible folder be prefixing it with a period (like "./.keys"). When creating your keychain you can view the invisible folder in the dialog window by pressing Command+Shift+".".
The answer to your question is "not possible today."
The technology is there today in the form of certificates which are supported already in all browsers. But to get what you want, the browsers would have to allow certificates to be added and managed in the "password manager" part of their user interface. People would want to sync them between devices etc.
Additionally, web sites would need similar changes for users to be able to manage the public keys stored on the web site, instead of managing their password.
The benefit of this kind of system would be that you never actually have to send your password (private key) to the web site you're logging in to. But otherwise, you still have all the management activities that you have today with passwords.
精彩评论