test\testrunner.js and try out
npm test for an example of seeing the client and server running through the full SRP6a protocol.
npm run-script build converts into a browserify module within the file
browser.js. See this article as an introduction to browserify.
For the definitions of the values discussed below please refer to the SRP design page. The following sequence diagram shows how to register a user with an SRP salt and verifier as demonstrated by the Thinbus Demo Application.
In the diagram above the user is shown a standard registration form which includes both the username (e.g email) and password fields.
and with the salt, email and password generates an SRP
verififer. Only the email,
salt and the
verifier are transmitted to
the server and the generated values are saved into the database keyed by the email.
Note Always use browser developer tools to inspect what you actually post to the server and only post the values shown in the sequence diagram as defined in the SRP design page. It is a protocol violation and security bug if the raw password is accidently transmitted to the server even if it is ignored by the server. It is also a protocol violation and a security bug if you accidently transmit the verifier to the browser.
The following sequence diagram shows how to login a registered user.
In the diagram above the user is shown a standard login form. They enter their email and password and click the login button.
salt and a one-time server challenge
B. Then client creates
a one-time client challenge
A and uses all the information to compute a password proof
M1. It then posts to the server
M1 as the users credentials. The server uses all the information (including a private part of the challenge to check the password proof). Only the email,
A and the password proof
M1 are transmitted to the server. Note that the server needs to hold the private challenge state
b that corresponds to the public challenge
B sent to the client. It can store this private state in a time limited cache.
There is an optional step
M2 is the server's proof of a shared session key to the client.
You can return
M2 proof is an additional check of the authenticity of the server; it confirms to trusted client code that the server knows the verifier matching the user password. This check is also proof that the client and server both generated the same shared session key
S. You can use
getSessionKey() on the client and server to get
H(S) a 256bit shared key that has not been transmitted over the network. This can be used for follow on cryptography such as http-hmac-spec signing of restful API traffic.
Note that you don't have to use AJAX for SRP. It is used in the examples to hide the fact that with SRP you need an additional round-trip to the server to generate a challenge using the users verifier. You can avoid using AJAX by splitting the username and password fields across two pages. The first page can send the username and the next page can have a hidden fields containing the user specific salt and the server challenge
B. This simply replaces the AJAX trip with an explicit page load.
Note as per RFC 2945 the user ID (usually their email) is concatenated to their password when generating the verifier. This means that if a user changes either their email address or their password you need to generate a new verifier and replace the old one in the database.
Note always use browser developer tools to inspect what you actually post to the server and only post the values shown in the sequence diagram as defined in the SRP design page. It is a protocol violation and a security bug to accidently transmit to the server anything else even if it is ignored by the server.
The object is intended to be a temporary object and should be deleted to erase all traces of the password. You must also destroy
the password form field the user typed their password into. The normal way to achieve destroying any traces of the password is to unload
the login page after every login attempt. This is trivial to do by reloading the login page upon authentication failure or by loading a main landing page upon successful login.
Note that the server has to remember the private ephemeral key
b that matches the public ephemeral key
B sent as a one-time server challenge to the user.
This requires storing
b either in the database, the server session or a server cache for the short duration of the login protocol.
You cannot pass this value back to the server from the client without compromising security.
The server should not use any values transmitted from the client other than those shown in the sequence diagram and
named in the SRP design page.
Note if you want to use the shared session key for follow-on cryptography you should use
client.getSessionKey() to retrieved the
session key from the thinbus object and destroy the thinbus object as discussed above. The typical way to do this is to put the session key into browser local session storage. Then you can unload the login page then load a main landing page that collects the session key
from storage. You can for example use the shared key for http-hmac-spec signing for restful API traffic.
Creating A Custom Large Safe Prime
The Java version of Thinbus has a command line tool and instructions how to use openssl to create safe prime see https://bitbucket.org/simon_massey/thinbus-srp-js/overview
- Use Thinbus SRP over HTTPS. Configure your webserver to mark session cookies as secure to prevent accidental use of HTTP. Configure HSTS to force HTTPS with your service. If your customers use a company supplied computer going via a corporate web proxy then HTTPS may be decrypted and monitored. HTTPS may be compromised due to things like bad certs in the wild. HTTPS may be compromised by bugs or misconfigurations such as Heartbleed. HTTPS alone cannot protected against leaking passwords into error messages in your webserver logs. SRP over HTTPS is much safer than either used alone.
- Check that the user isn't using a password that is in the HiBP database. HiBP lets you query using the first few characters of the hash of the users passwords. You can check for an exact match of the hash in the results and refuse to let the user use a password that is in the public database of leaked passwords.
- Use a custom large safe prime number
Nusing the instructions above. Tip: Check on the browsers and hardware you are targeting that the math runs fast enough for a good user experience for your chosen bit length.
- Make the salt column in the database
not nulland add a uniqueness constraint.
- Use symmetric AES encryption with a key only visible at the webserver to encrypt the verifier
vvalue within the database. This protects against off-site database backups being used in an offline dictionary attack against
- You can prevent privileged accounts from logging in using legacy browsers by checking
random16byteHex.isWebCryptoAPI()when fetching the user salt; simply abort the protocol for privileged accounts when secure random numbers are not available at the browser. If you allow the use of browsers that don't have the
WebCryptoAPIsecure random number APIs then the fallback random generator hashes
window.cookieas part of the generator seed. Consider adding a secure random cookie to help seed the fallback generator.
- Don't include any JS files or any CSS files from external sites onto your login page.
- Count the number of failed password attempts and present the user with a CAPTCHA after a dozen attempts. This slows down scripted online dictionary attacks. Consider suspending the account (possibly temporarily) after a large number of contiguous failed attempts to defeat someone carefully researching a user then trying to guess their likely password.
The name Thinbus is a play on the name of the SRP Java library Nimbus. Thinbus NPM (this repo) is tested against Thinbus JavaSciprt taken from the Java version, which in turn is testing against Nimbus, which gives higher confidence in its correctneess. Nimbus has had a lot of eyes look at it over the years and was carefully check against other Java SRP library code and the example code provided by the inventor of SRP.
- pysrp_thinbus is a fork of pysrp which is compatible with Thinbus so that you can use Python on the server.
Copyright 2014-2017 Simon Massey Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.