I’ve just published my eighth Pluralsight course – Secure Account Management Fundamentals – and it’s all about the things we need to do to properly look after the valuable customers that use the services we developers build. Normally when I launch a new course I’d write up a bunch of detail on what it’s all about but this time, I thought I’d reproduce a collection of the discussions I’ve had with many people over many years about secure account management concepts.
I assure you, I’ve had all these conversations many times and I keep seeing the same fundamental misunderstandings not just with discrete security concepts but with the logic flow that surrounds account management processes. Treat this as “stories from the trenches” which the new Pluralsight course sets out to directly address.
Dev: I’m going to build a website where people can register, get a nice welcome email then log in and do a bunch of stuff under their identity.
Me: Cool, will you let people register multiple times with the same email address?
Dev: No way! That’d cause all sorts of problems, I’ll tell them if they already have an account on the system.
Me: But does that mean an attacker can simply enumerate through a list of email addresses and see which ones exist in your system.
Dev: Uh, kinda… does it really matter though?
Me: It can matter, it depends if there’s a reasonable expectation of privacy on behalf of the account holder. We can sort that out by verifying the identity via the welcome email you were going to send them anyway. Have you planned any anti-automation defences on the registration form?
Dev: Why would we bother, it’s just registration?
Me: What if someone auto-registers a million random people using a freely available email list and they all get a welcome email they didn’t expect?
Dev: Why on earth would anyone do that?! What’s the upside for them? And what’s the damage to the system?
Me: Well there’s reputation damage for a start, then there’s the damage it does to your spam rating when people start flagging the emails as spam and jeopardising your ability to deliver the legitimate ones. Attackers don’t always need a reason, it’s often just “lulz”.
Dev: Bugger. What do we do?
Me: We can talk about anti-automation techniques and the trade-off between security and usability. Moving on, how are you going to store their password?
Dev: Oh I’ll encrypt it with a hash!
Me: Which one?
Me: Are you going to encrypt it or hash it?
Dev: I mean I’m going to use SHA1 with a salt so yeah, I’m going to hash it.
Me: Righto, so you realise that a salted SHA1 hash is pretty much useless right?
Dev: Ah, but it’s a one-way hash so you can’t un-hash it and rainbow tables won’t work because it has a salt.
Me: Yeah, but when you can compute 30 billion (that’s right, with a “B”) SHA1 hashes per second with consumer hardware, cracking even salted hashes is a cinch.
Dev: Uh, right…
Me: No dramas, there are much stronger alternatives available we can talk about. What about the logon – you going to allow multiple simultaneous sessions?
Dev: I hadn’t really thought about that – should I? What’s the problem?
Me: You should think about it then consider if it actually matters given the nature of your app – in many cases it doesn’t. What about brute force protection on the logon?
Dev: That one is easy, I’ll just lock the account out if there are 5 failed attempts!
Me: So I can lock anyone out of their account if I know their username?
Dev: Good point, how about this – no lockouts!
Me: Well no lockouts can be good if you have other mitigations in place, but what happens if a bot starts hammering your service with millions of logon requests?
Dev: Hmm… I’ll have a black list of IP addresses and block any that show suspicious activity like that.
Me: So what if it’s a botnet distributed across tens of thousands of IP addresses?
Dev: They do that?!
Me: Yeah, it’s a thing, we’ll should talk about rate limiting and service degradation later on. There’s a bunch we can do around fraud detection and prevention as well. You going to allow a “remember me” feature?
Dev: Isn’t doing that a security risk?!
Me: That’s a relative question – it can be in certain scenarios but it’s a pretty critical component of the user experience in other scenarios; security isn’t just all about making things hard on people you know!
Dev: Gotcha, we can look at encrypting the username and password with Base 64 and putting that in a cookie then when the user comes back…
Me: Yeah, no! I’ve seen that done many times before but just no! Let’s move onto changing account details – can users go back in and edit the info they provided at registration?
Dev: Yep, and I know where you’re going with this – they can’t change their password without providing the old one first so that’s secure.
Me: What about their email? Can they change their email without providing the original password?
Dev: Yeah, but that won’t let them change the password!
Me: You’re gonna build a password reset feature right?
Dev: Oh course!
Me: Where are you going to send the reset email to?
Dev: Oh crap. Ok, we’ll request a password confirmation for an email change too.
Me: Cool, now how are you going to handle it if the attacker already has the user’s credentials?
Dev: Well that’s not going to happen because you’re going to help us secure the system and they won’t be able to get them out from anywhere!
Me: True, but what happens when they’ve reused their credentials elsewhere and then they’re breached and dumped publicly? Or there’s a successful brute force attack on another system and the attacker gets their creds from there?
Dev: Well that’s just sloppy behaviour on behalf of the user so it’s their problem!
Me: Perhaps, but if an attacker uses those creds to compromise an account on your system you know where the user is going to lay the blame, right?
Dev: But there’s nothing you can do about that – it’s game over once their username and password are leaked!
Me: Not quite, we can use other verification channels for key account activities such as changing attributes which would enable account takeover. How are you going to tackle the password reset feature?
Dev: I’ll just email the existing password.
Me: You can’t do that because you’re storing it as a cryptographic hash which can’t be reversed.
Dev: Ok, I’ll just email a new one then.
Me: Well you can’t really do that either because now you’re sending it to someone over an insecure channel and then persisting it in insecure storage.
Dev: But I’ll tell them they should change it right away – it’s in their best interest!
Me: Yeah, but they won’t, plus this locks them out of their account until they retrieve the new password so an attacker can DoS the victim just by initiating the reset process.
Dev: You’re not leaving me with many options here!
Me: It’s not actually hard, we just need a time-limited nonce in a link to the site that grants them the ability to set a new password. What are you going to do if someone enters an email that doesn’t exist in the reset feature?
Dev: Well I’ll have to tell them that’s an incorrect or non-existent address.
Me: And there’s your enumeration risk again – you’re disclosing information about who has an account on the site and who doesn’t and that creates a bunch of privacy risks.
Dev: You just like making life hard on me, don’t you?
Me: It’s actually not hard, we can use the same email channel to either initiate the reset process or advise the user that they don’t have an account on the system. Let’s move on – how are you doing logoff?
Dev: Well fortunately that’s one you can’t do insecurely! It’s just a page that expires the auth token therefor logs them out.
Me: Ok, so that’s just an HTTP GET to something like /logoff right? How are you going to mitigate against the risk of CSRF?
Dev: That’s not really a risk though is it? I mean what can the attacker get?
Me: Well if it’s just a GET request to a resource then the attacker could always stand up a page that embeds that path in an iframe or even as the source of an image and if the user loads the page, they’re auto logged out.
Dev: Is that really a risk though?!
Me: Depends on the system; it can effectively be a denial of service attack if the attacker can get their page loaded on the victim’s browser and, say, cause it to keep hitting the logoff path by way of a meta refresh so that they’re logged out almost immediately after logging on.
Dev: But you’ve still gotta get the attacker’s page loaded in the victim’s browser, how are you going to do that?
Me: Heaps of ways, for example tweeting them a link with something alluring like the promise of a free pass, sending it via an email phish or even serving it via an ad network with malicious script. It happens enough that CSRF is still up there in the OWASP Top 10.
Dev: So you just make the logoff a POST request then and you’re done?
Me: That’s not enough on its own, you need to protect this attack in the same way as you’d protect from any other CSRF attack and that’s by using anti forgery tokens. It’s a piece of cake and most frameworks have native constructs to help you with it.
Dev: Ok, so at least that’s it right? All good? All done?
Me: Well… that’s the fundamentals but there are a heap of additional considerations. For example, have you thought about using an identity provider like Microsoft Azure Active Directory or even OpenID Connect so that you make a bunch of this someone else’s problem? Ok, they have their downsides too but it’s worth considering.
Dev: I like that “someone else’s problem bit”! What else?
Me: Have you thought about using a web application firewall, perhaps via a service such as CloudFlare? It doesn’t entirely get you off the hook security wise, but it can be very advantageous not just for security, but for performance too.
Dev: Interesting. Pricey?
Me: Well it starts at free and works up from there so not necessarily.
Dev: Oh – speaking of additional defences, what about two factor authentication?
Me: 2FA or two step auth can be awesome defences, but you know there’s a risk where the attacker can lock the victim out of their account, right?
Dev: Hang on – 2FA isn’t just all rainbows and unicorns?!
Me: Nope, and while you’re getting your hopes dashed, remember you also want to have a think about how you protect the account management facilities from attackers inside the organisation.
Dev: Ah, but everyone I work with is very nice and trustworthy!
Me: They probably are, but that doesn’t mean they might not end up with malware on their machines and serious problems Sony Pictures style. The design of your account management facilities and how you approach the principle of least privilege can have a big impact on just how bad it gets in a scenario like that. Oh – and while we’re not trusting people, you also want to consider how you’re going to protect against the threat of customers of the site being lured in by social engineering attacks such as phishing emails so yeah, you’ve got a bit to think about yet.
Dev: Ok, that is seriously not my problem!
Me: Well we’re back to the earlier point about their sloppy practices potentially making your site look bad as that’s where they first see the risk surfaced. There’s much more to security than just technical controls, you need to consider the social aspect and how views like this might adversely impact you.
Dev: So now I’m a bit scared about how much I hadn’t really thought of that goes into these features!
Me: Better scared now than remorseful later :)
This is the thing about security in general and how we implement account management in particular – there are a heap of angles to it. There are all the fundamentals of security, things like SQL injection and XSS and SSL (although we really should be saying TLS in the wake of POODLE), but there are also discrete issues around process flow and logic errors. On top of that you’ve got a real balance between security and usability to strike that’s more evident in these features than most other aspects of application security. It’s one of the more impactful areas to get wrong – people tend to get a bit uppity when their accounts are compromised and the impact may range from the relatively benign leaking of email addresses all the way through to your personal nudie pics being put on public display.
This course covers everything you’ve read above plus a whole heap more. It’s over seven hours of content – quite a bit more than I’d planned – but it just started to write itself once I got going. There’s a huge amount of effort in it and I hope everyone who views it both enjoys watching it and takes away some really valuable knowledge that makes a tangible difference to their work.
The course is live right now under Secure Account Management Fundamentals on Pluralsight. Enjoy!