The problem with accounts
As I mentioned in my first journal post, I don't much care for usernames and passwords. In fact, I've been systematically planning their demise since I started in software development - I'll let you know how that goes. This is especially true in mobile development. We each have our own device,1 so why not just associate an account with the device and leave it at that? Nobody needs to create a username and password for that to happen.
User defined passwords are a security disaster waiting to happen. There's only so much that we, as developers, can do to prevent our users from making mistakes. The most obvious of which is the general population's penchant for using hideously insecure sequences of characters to prevent unauthorised access to their data, but what I consider to be the much greater threat is password reuse. Despite how much I try to convince all of the people in my life that they're putting themselves at risk with this practice, it's still something I see all the time. I definitely don't want to be blamed for someone's online credit card account being breached because they used the same password for my lowly sync engine.
What's the solution?
Those of us with good sense know to use something like 1Password to make sure that all of our passwords are different, and hopefully just a series of random characters. But do you know what's even better than random characters? Time-limited random characters. And do you know what's really good at generating random characters? Computers. It's almost as if this is what we were supposed to do all along...
One notable, recent, example of an attempt to circumvent usernames and passwords is Marco Arment's login system for The Magazine's website.2 It works by sending a temporary URL to the email address associated with your account, which then grants you access to the account on that machine. My issue with this idea is that it's effectively delegating authentication to your email provider; if an attacker compromises a user's email account, they can compromise the user's account on your service.
This is how I envisage the login process for Airmail:
- A user creates a new account, which they are immediately connected to. They don't need to give me anything, I can generate a UUID to refer to the device they're using.
- The user requests an invitation for their significant other to join the account.
- The Airmail server generates a random sequence of characters, which is securely returned to the user. Let's call it an invitation code.
- The user shares this invitation code with their significant other.
- The user's significant other elects to join an account and uses the invitation code to gain access to the same data.
- The invitation code is invalidated.
Simple. Secure. And of course: the invitation codes would expire if not used within a reasonable timeframe.
By handling the process like this, the user is never asked to give any personal information that could potentially be compromised. There is also a much lesser chance that an attacker would be able to gain access to the account even if they did get hold of an invitation code. But there are still issues that need to be solved.
Imagine that Adam creates an account and invites Betty to join. Then if Adam needs to delete and reinstall the app for any reason,3 Betty can invite him back to the account and everything continues as normal. However, in the unlikely event that both Adam and Betty delete the app simultaneously, nobody is left to generate invitations and the account is abandoned. This is a problem.
There needs to be a way for the Airmail server to generate an invitation code for the account in this situation, but without compromising the security of the account - multi-factor authentication is required. My current thinking is that I can accomplish this with a recovery key (possession factor) and some information about the account data (knowledge factor) to verify the user. I'm still ironing out the details in my head, but I'm relatively sure that I can handle this manually via support requests. It should be a rare occurrence in any case.
Continuing with Adam and Betty, it stands to reason that Adam is the account owner because he created the account and invited Betty to join. There are a few maintenance tasks that will need to be possible, which would usually be handled by an account owner:
- Extending the subscription.
- Inviting new collaborators.
- Revoking access for collaborators.
We need to consider the first scenario in account recovery again: Adam has deleted and reinstalled the app, and needs to regain his access to the account.
By assuming that Adam is the account owner and only allowing the account owner to generate invitations, Betty wouldn't be able to invite him back onto the account and he would have to go through multi-factor authentication. I don't like this.
By allowing all users to generate invitations, but only the account owner to perform the other maintenance tasks, Betty can still invite Adam back onto the account. However, the device that was considered the account owner now isn't active anymore, so nobody can perform the other maintenance tasks (without potentially going through multi-factor authentication). I don't like this either.
My preferred solution is that nobody is the account owner. The server will not distinguish between the user that created the account and any subsequently invited users, and the only difference for Adam and Betty is that Adam would have the recovery key for the account - Betty can still perform all maintenance tasks. This falls down when imagining a scenario in which someone with malicious intent has gained access to the account, and can now revoke the owner's access to their own account. I consider this to be another rare occurrence, and the existence of the recovery key should provide an adequate workaround.
I don't need usernames and passwords, I can create a much more secure system by taking away the user's ability to define any of the keys that grant access to their account. I feel I should clarify: I'm in no way a security expert - far from it. I welcome anyone to poke holes in this system or suggest better solutions to the problems I've described already. Hit me up on twitter.