User Authentication Best Practices Checklist

User authentication is the functionality that every web application shared. We should have perfected that a long time ago, having implemented it so many times. And yet there are so many mistakes made all the time. Part of the reason for that is that the list of things that can go wrong is long. You can store passwords incorrectly, you can have a vulnerably password reset functionality, you can expose your session to a CSRF attack, your session can be hijacked, etc. So I’ll try to compile a list of best practices regarding user authentication. OWASP top 10 is always something you should read, every year. But that might not be enough. So, let’s start. I’ll try to be concise, but I’ll include as much of the related pitfalls as I can cover – e.g. what could go wrong with the user session after they login: Store passwords with bcrypt/scrypt/PBKDF2. No MD5 or SHA, as they are not good for password storing. Long salt (per user) is mandatory (the aforementioned algorithms have it built in). If you don’t and someone gets hold of your database, they’ll be able to extract the passwords of all your users. And then try these passwords on other websites. Use HTTPS. Period. (Otherwise user credentials can leak through unprotected networks). Force HTTPS if user opens a plain-text version. Mark cookies as secure. Makes cookie theft harder. Use CSRF protection (e.g. CSRF one-time tokens that are verified with each request). Frameworks have such functionality built-in. Disallow framing (X-Frame-Options: DENY). Otherwise your website may be included in another website in a hidden iframe and “abused” through...

OWASP Dependency Check Maven Plugin – a Must-Have

I have to admit with a high degree of shame that I didn’t know about the OWASP dependency check maven plugin. And seems to have been around since 2013. And apparently a thousand projects on GitHub are using it already. In the past I’ve gone manually through dependencies to check them against vulnerability databases, or in many cases I was just blissfully ignorant about any vulnerabilities that my dependencies had. The purpose of this post is just that – to recommend the OWASP dependency check maven plugin as a must-have in practically every maven project. (There are dependency-check tools for other build systems as well). When you add the plugin it generates a report. Initially you can go and manually upgrade the problematic dependencies (I upgraded two of those in my current project), or suppress the false positives (e.g. the cassandra library is marked as vulnerable, whereas the actual vulnerability is that Cassandra binds an unauthenticated RMI endpoint, which I’ve addressed via my stack setup, so the library isn’t an issue). Then you can configure a threshold for vulnerabilities and fail the build if new ones appear – either by you adding a vulnerable dependency, or in case a vulnerability is discovered in an existing dependency. All of that is shown in the examples page and is pretty straightforward. I’d suggest adding the plugin immediately, it’s a must-have: <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>3.0.2</version> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> Now, checking dependencies for vulnerabilities is just one small aspect of having your software secure and it shouldn’t give you a false sense of security (a sort-of “I have...

Using Trusted Timestamping With Java

Trusted timestamping is the process of having a trusted third party (“Time stamping authority”, TSA) certify the time of a given event in electronic form. The EU regulation eIDAS gives these timestamps legal strength – i.e. nobody can dispute the time or the content of the event if it was timestamped. It is applicable to multiple scenarios, including timestamping audit logs. (Note: timestamping is not sufficient for a good audit trail as it does not prevent a malicious actor from deleting the event altogether) There are a number of standards for trusted timestamping, the core one being RFC 3161. As most RFCs it is hard to read. Fortunately for Java users, BouncyCastle implements the standard. Unfortunately, as with most security APIs, working with it is hard, even abysmal. I had to implement it, so I’ll share the code needed to timestamp data. The whole gist can be found here, but I’ll try to explain the main flow. Obviously, there is a lot of code that’s there to simply follow the standard. The BouncyCastle classes are a maze that’s hard to navigate. The main method is obviously timestamp(hash, tsaURL, username, password): public TimestampResponseDto timestamp(byte[] hash, String tsaUrl, String tsaUsername, String tsaPassword) throws IOException { MessageImprint imprint = new MessageImprint(sha512oid, hash); TimeStampReq request = new TimeStampReq(imprint, null, new ASN1Integer(random.nextLong()), ASN1Boolean.TRUE, null); byte[] body = request.getEncoded(); try { byte[] responseBytes = getTSAResponse(body, tsaUrl, tsaUsername, tsaPassword); ASN1StreamParser asn1Sp = new ASN1StreamParser(responseBytes); TimeStampResp tspResp = TimeStampResp.getInstance(asn1Sp.readObject()); TimeStampResponse tsr = new TimeStampResponse(tspResp); checkForErrors(tsaUrl, tsr); // validate communication level attributes (RFC 3161 PKIStatus) tsr.validate(new TimeStampRequest(request)); TimeStampToken token = tsr.getTimeStampToken(); TimestampResponseDto response = new TimestampResponseDto(); response.setTime(getSigningTime(token.getSignedAttributes())); response.setEncodedToken(Base64.getEncoder().encodeToString(token.getEncoded()));...

Enabling Two-Factor Authentication For Your Web Application

It’s almost always a good idea to support two-factor authentication (2FA), especially for back-office systems. 2FA comes in many different forms, some of which include SMS, TOTP, or even hardware tokens. Enabling them requires a similar flow: The user goes to their profile page (skip this if you want to force 2fa upon registration) Clicks “Enable two-factor authentication” Enters some data to enable the particular 2FA method (phone number, TOTP verification code, etc.) Next time they login, in addition to the username and password, the login form requests the 2nd factor (verification code) and sends that along with the credentials I will focus on Google Authenticator, which uses a TOTP (Time-based one-time password) for generating a sequence of verification codes. The ideas is that the server and the client application share a secret key. Based on that key and on the current time, both come up with the same code. Of course, clocks are not perfectly synced, so there’s a window of a few codes that the server accepts as valid. Note that if you don’t trust Google’s app, you can implement your own client app using the same library below (though you can see the source code to make sure no shenanigans happen). How to implement that with Java (on the server)? Using the GoogleAuth library. The flow is as follows: The user goes to their profile page Clicks “Enable two-factor authentication” The server generates a secret key, stores it as part of the user profile and returns a URL to a QR code The user scans the QR code with their Google Authenticator app thus creating a...

Protecting Sensitive Data

If you are building a service that stores sensitive data, your number one concern should be how to protect it. What IS sensitive data? There are some obvious examples, like medical data or bank account data. But would you consider a dating site database as sensitive data? Based on a recent leaks of a big dating site I’d say yes. Is a cloud turn-by-turn nagivation database sensitive? Most likely, as users journeys are stored there. Facebook messages, emails, etc – all of that can and should be considered sensitive. And therefore must be highly protected. If you’re not sure if the data you store is sensitive, assume it is, just in case. Or a subsequent breach can bring your business down easily. Now, protecting data is no trivial feat. And certainly cannot be covered in a single blog post. I’ll start with outlining a few good practices: Don’t dump your production data anywhere else. If you want a “replica” for testing purposes, obfuscate the data – replace the real values with fakes ones. Make sure access to your servers is properly restricted. This includes using a “bastion” host, proper access control settings for your administrators, key-based SSH access. Encrypt your backups – if your system is “perfectly” secured, but your backups lie around unencrypted, they would be the weak spot. The decryption key should be as protected as possible (will discuss it below) Encrypt your storage – especially if using a cloud provider, assume you can’t trust it. AWS, for example, offers EBS encryption, which is quite good. There are other approaches as well, e.g. using LUKS with keys...