SCRAM is a new mechanism designed to let you sign in into your servers much more securely than with existing mechanisms. It involves applying various algorithms to your password to make it extremely difficult to hack.
The SCRAM-SHA-1 SASL mechanism was added to the XMPP spec, and replaces the legacy DIGEST-MD5 mechanism. Its various security features include hashed passwords being send over the internet, and hash passwords being stored on disk. Attackers which can read the network traffic or the server's password database are unable to do any harm.
I just finished a SCRAM-SHA-1 implementation for Psi as part of my GSoC project. There are test cases to write and wider testing to be done, but we now have a working implementation.
What does this mean for Psi users? Well, usually, when you don't want to enter your password each time you login, you tell Psi to save it. Most clients, if not all, store it in clear text form if you tell them to store it at all. This is fairly insecure, and anyone with access to the computer could get access to your password. It's a common security advice that you shouldn't use the same password for all your accounts on various services on the internet. However, human laziness is a powerful force. So, if you use the same password for various services, and someone malicious gains access to it, she/he can gain access into all the other accounts where you used that password.
Now SCRAM comes into play. If your server supports this, and your client supports this, you can have them store your password in a form not very usable by attackers. Thankfully Prosody got some new authentication backend APIs thanks to Jeff Mitchell. You can read more about that in Jeff's blog post. Effectively this means that if a malicious person gains read access to your network or the server, they can't do anything, and if they gain access to your computer, they can do nothing more than login into your jabber account.
What are the consequences of using a hash to login? It basically comes down to support. It requires support by both the client and the server. Only when both have support do you get the full security SCRAM offers. On client side, since you're clearing your plaintext password you have to login using SCRAM in the future. On the server side, you're storing the iteration count, salt and the and two keys instead of the plaintext password. This reduces your possible login methods to only PLAIN (this should only be done over TLS) and SCRAM-SHA-1.
This is currently only available in a development branch. It'll soon get merged into the main branch. To enable this in Psi, first make sure your server supports SCRAM. Then go to the Misc tab in your Account Properties dialog and check the checkbox labelled “Store password as salted hash...”.
Apply the changes. Reconnect.
Now when you visit your Account Properties dialog, you'll notice that the input box for your password is empty. YAY.
So what's next on the agenda for my Google Summer of Code project? Currently I'm a little behind but I'll get started on implementing stanza acknowledgement and session resumption of XEP-0198 the next couple of days to get back on the track.
That's right DIGEST-MD5, your job is done here. Now it's time for the new kid to take up your place.
Those of you who ever tried to actually implement the DIGEST-MD5 SASL mechanism for authentication know that it suffers from quite a few problems, including but not limited to a variety of different implementations with a variable level of compliance to the DIGEST-MD5 RFC 2831. These interoperability problems make it quite hard to get a new implementation working with most of the already existing implementations.
SASL mechanisms are designed to be protocol-independent. That's basically the whole idea about SASL; to abstract the authentication part out of the application protocols, and standardize it. However DIGEST-MD5 already started off on the wrong foot.
Intending to interoperate with digest authentication used for HTTP, the requirement for ISO 8859-1 encoding support was added. However XMPP for example, designed internationally and using latest developments in the DNS area, supports UTF-8 usernames, passwords and IDNs. This makes it hard to store a hashed version of the password since you need to be prepared for either encoding, ISO 8859-1 and UTF-8.
Here comes SCRAM to the rescue. So far I have implemented the basic parts of it in my SASL library which is written in Lua and is a part of Prosody. In the SCRAM draft you can read about the design considerations which are clearly more modern and focused on more international usage.
- Usernames and password are Unicode and are to be string prepped before usage; a feature DIGEST-MD5 doesn't have.
- You can now easily store the user relevant authentication information in a database which isn't by itself sufficient to impersonate the user; this might be possible somehow with DIGEST-MD5 but it clearly hasn't been made easy for the developers (leading to XMPP servers storing plaintext passwords).
- You can simply swap out the basis, the hashing algorithm used, in SCRAM. This makes the mechanism more future proof and secure, unless design issues are found in the protocol itself.
- SCRAM has been designed to be easier to implement than DIGEST-MD5. I totally agree with this. Message parsing has been made easier by using no quotes on values; DIGEST-MD5 used them but only on some values.
One last note on interoperability: I've continuously tested my implementation against Simon Josefsson's implementation for GSASL, which was quite easy to set up thanks to GSASL's command line interface. Shortly after, I also did interoperability testing against the SCRAM implementation by Paul Aurich for Pidgin, in which we both fixed some bugs. A Prosody instance is still running for interoperability testing at scram-interop.ayena.de. Last but not least, we're working nicely against Swift; however no end-users can be happy about that currently;).
So client and server developers, get ready for SCRAM and implement support for it for a more interoperable future; not to forget its being the MTI mechanism for the next XMPP RFC iterations.
Version 0.2.0 has been released just one month after version 0.1.0 and four months after development began. With currently nearly one month between a release and the next we have a good release frequency which is fairly important for a project, especially for one which focuses on ease of prototyping new features in and a protocol around it like XMPP with is evolving pretty fast.
With consent of all the other developers, Waqas and my humble self, Matt dictated the use of Lua for the server which has quite some advantages.
Since it's an interpreted language you don't have to wait for building to test some changes you made or don't need stuff like autoconf to build your project cross-platform. However we have some binary modules for encryption and more low-level stuff.
The resulting server is pretty fast, already implements quite some XEPs while not being a memory beast like eJabberd. Not to forget the nice side affect of using Lua as implementation environment which is that you can easily add new protocols to it and test them. This should help us to push the interesting and important XEPs server side so that the client developers get in charge to implement them on their side.