Storing Secrets
Something that has been annoying me recently with my bank has been that their website tells me that they will never ask for my password over the phone. And then their call centre asks me for my password. Over the phone. Of course the call centre doesn't mean my website password - they mean the special 'ultra-secure 5ekr1t code phrase', but they don't have a good, universally understood word to use for that. Hopefully they'll work one out, but they appear to have got the message anyway.
This got me to thinking about how these phrases are used, and how insecure they are in reality. After all when I store a website password I go to significant lengths to ensure that the same password is not represented by the same string of characters in my database. How vulnerable are our secrets in the databases of organisations we do business with?
Simple Password Storage
Surprisingly often people do store passwords in databases in plain text, so that should their website get hacked someone would quite possibly be able to download the whole password database. Please feel free to name and shame these organisations in the comments below. My own pet hate in this regard is the 'Mailman' mailing list software: by default on 'mailman day' - the first day of each month - it sends me my password. In plain text.
Of course many developers recognise this flaw, and work around it by using a one-way hash to obscure the password. Usually they choose md5 for their hashing algorithm though, and they often fail to use a 'salt' to randomise the plaintext prior to hashing. This means that even though a password might seem obscure like 'Supercalifragilisticexpialidocious!', and no doubt it will hash to something that seems obscure like 'a7290d426b6a1764af6fd7fba5db214e', but you can often find it straighforwardly by looking it up through one of the friendly reverse hash lookup websites. There's even a Digest::MD5::Reverse perl module on CPAN to interface to a bunch of these in a more automated way! Oh dear.
One way to go beyond this is using a 1-way hashing algorithm, with a random salt included into the plaintext before the hashing, so that if (god forbid) two users had 'password' for their password I might see two rows in my database like:
davical=# select username, password from usr;
username | password
-------------+------------------------------------------------
user1 | {SSHA}qCctCH5dirYCf29uxJiE68LvmLRDdnBkbldiWlE=
user2 | {SSHA}y8yOzjoh9fSkVwLaXGoVtWdiIYxmU2FCb2dOZXc=
(2 rows)
When the user wants to log in I apply the same transformation to their incoming password (appending the same salt) and compare against my stored hash. If they match then it must be the same password they used previously. Storing passwords in this way secures them from casual, or even reasonably determined access, although naturally they can still be logged at the beginning and end of the communication - or even in the middle, if we didn't encrypt that bit!
The PHP function I use to salt and hash the password is as follows:
/**
* Make a salted SHA1 string, given a string and (possibly) a salt. PHP5 only (although it
* could be made to work on PHP4 (@see http://www.openldap.org/faq/data/cache/347.html). The
* algorithm used here is compatible with OpenLDAP so passwords generated through this
* function should be able to be migrated to OpenLDAP.
*
* If no salt is supplied we will generate a random one.
*
* @param string $instr The string to be salted and SHA1'd
* @param string $salt Some salt to sprinkle into the string to be SHA1'd so we don't
* get the same PW always hashing to the same value.
* @return string {SSHA} followed by a base64 encoded SHA1 of the salted string.
*/
function session_salted_sha1( $instr, $salt = "" ) {
if ( $salt == "" ) {
$salt = substr( base64_encode(sha1(rand(100000,9999999),true))), 2, 9);
}
return ( sprintf("{SSHA}%s", base64_encode(sha1($instr.$salt, true) . $salt)));
}
What about Secret Code Phrases?
The problem with these secret code phrases, apart from all of the forgetability and guessability problems that have repeatedly been identified elsewhere, is that they are much less likely to be stored in a one-way hash. Are you going to ask your call-centre staff to type in the customer's secret code phrase? Didn't think so. And if you did it's going to add pronouncability issues to the whole mix.
So this means that those organisations who have our secret code phrases in their database will, in all likelihood, have them stored directly as plain text, displaying them to the random call-centre staffer along with all of our other account details, and especially making them vulnerable to accidental disclosure. Disclosure of a sort that doesn't necessarily involve knowing they have been disclosed.
Proliferation of Use
These things provide the appearance of security - 'Security Theatre' as Bruce Schneier terms it - and because of that they're taken up in a kind of a cargo cult of security: "if the banks do it that way it must be a really good form of security". This makes the problem much worse, because now I have to remember a secret code phrases not only for banks, but for ISPs, phone companies, online auction websites, and so on.
How many mother's maiden names, favourite teachers and friend's phone numbers do I have? I'm sure I'm at well up whatever curve it is that measures the number of passwords a person has, because five years ago I had so many I started to store them all in an encrypted database - protected by a yet another password, of course. Now in order to get my story straight I have to store my 'secret code phrases' in there too.
If I didn't store my secret code phrases in that database, I'd obviously be re-using them everywhere, from a very small set - perhaps the same one that everyone around me overhears, every time I have to ring my bank to authorise another payment from my account.
Because the proliferation of use is not just the breadth of wannabe thespians hoping to climb on the stage of this latest play, but the way they want to use it all the time, too. In fact the only conversation I've had recently with my bank where they didn't want it was when they rang me. Obviously I was the only person who could answer a phone in my house, right? It isn't just security theatre: I think we can see that this analogy belongs much deeper into the sub-genre of 'Security Farce'.
Is there a solution?
I don't have any easy answers - other than the ones to my security questions, of course - but some improvements are possible.
Other banks have quizzed me about stuff like recent expenditure or credit card limits from time to time, but I've usually passed those tests by reading my last bank statement - or failed them by not having it to hand! I don't really think that the answers can lie in that direction because the information is only quite loosely tied to my identity.
For some parts of the call-centre handling of secret code phrases there are changes that could make them more secure, but in the fairly short term these organisations need to find a different way to perform these out of band identity checks.
For the actual storage of the code phrases it would be a marginal improvement if the database did not contain the actual phrase. Perhaps it could be encrypted with some application-known key, so that it can be unencrypted when it needs to be displayed, but never stored in the clear. Of course there's still the problem with that key...
Verification of the secret code phrase could be done by someone not involved in the transaction, so that the call could be temporarily passed into a 'verification stream' where a different person performed the verification step without the context of the account details or enquiry. Though this sort of complexity seems unlikely with call centres seemingly being outsourced to the cheapest supplier.
One thing does seem likely to become increasingly true: there is less and less private data in our lives, and every time we share one of these little nuggets with our bank, or our electricity company, or our on-line associates-we-call-friends, is one more chance that it escapes into the hands of the foaming-at-the-mouth-terrorist-cracker-communist-nazi-right-wing-religious-fruitcake hordes.
The highest bar for personal verification which any of my banks currently sets for me is a random choice from a set of personally entered questions, with a set of personally entered answers, for which I have to enter two randomly selected characters using my mouse. That's not bad for safe verification, and I'd have to be really impressed with their security if that was stored in the database by a passphrase-protected encryption key. With that bank I don't know what they do over the phone - I assume they've concluded they can trust my logged on persona enough that I can do what I want online, consequently I haven't had to call them and share those secrets with everyone in earshot.
Maybe paranoid freaks like me will go back to a chequebook and close down on-line access to their bank accounts entirely when they find themselves having to supply a skin scraping in order to authorise their next $500 payment. "Please insert your finger in the AccuYou(tm) BloodSucker(tm) to proceed with this payment" - well, I guess it might cut down my spending! In any case, biometrics need to be understood before they can be used effectively and appropriately - and remotely over the phone is probably not one of the ways that they can be trusted to work.
Flattr
A question
So, there's this fairly popular online trading site in NZ which allows users to request a password reminder, and then emails their passwords back in plain text.
Is there any way that they can be storing the passwords with meaningful encryption? If the server accessing the passwords has a key available to decrypt the passwords, then are the passwords effectively stored plaintext anyway?
Or could this somehow be a secure setup, despite the recoverability of their password storage method?
I'm fascinated. The site in question is, er, "fairly big" and I'm sure they must have some security geeks on their team, right?
Returning your password to you in plaintext
If the site can return your password to you in plaintext then it is still possible they have encrypted it for database storage. Using a salted hash as I describe above would mean they could not do that, but they may be using a reversible encryption instead. The application would then only need the decryption key to be able to decrypt the password and hand it back to you.
Given that the password is returned to you essentially 'out of band' (i.e. by e-mail in response to a web request) it could even be arranged that the web application encrypted with a public key, which it was unable to reverse, and that the password recovery process was the only piece which 'knew' the private key, in order to decrypt it and send it back to you.
That seems like a lot of work, which would essentially have been done in order to avoid the work of sending a time-limited alternate password if someone went through the password replacement scheme. Of course password recovery is something I should have mentioned above, because it is required when you follow a scheme like the one above: you have to allow password recovery to create a temporary password. In order that you not provide opportunities for annoying denial of service problems where someone repeatedly requests a new password for a person's account, the alternate password needs to be valid at the same time as the normal one, which adds a little complexity to the login process.
In my own apps I do this by having a temporary password table in the database, which I also check on login if the primary password fails validation. Logging in to an account will delete all rows in that table for the account that just logged in, so a temporary password is only valid for a single time, and it also sets an expiry timestamp on the password after which time the alternate won't be checked against.
In the general case, however (and probably in the case of TradeMe as well), it seems that Occam's Razor will apply.
Cheers,
Andrew.
Don't hold your breath...
...my wife had exactly the same thing with ASB a few months ago - even worse, it was for a marketing call. When we phoned the call centre to raise our concerns, we were told they would raise it with the caller. It seems they need to review their processes.
Having come from the UK a couple of years ago, I was a bit shocked with the approach taken by some banks over here - I regularly get emails from ASB, often including links back to the bank site, which invariably would only be a click or two away from a login page.
All this does is desensitize people to clicking on a link in an email and entering a password. I seem to recall Lloyds TSB in the UK typically stating they would never ask for a password, and never having links back to their site within the body of the email.
I have on three occasions now halted a conversation when asked for a password or other personal information, politely explained my objections, and then decided whether or not to continue with the *incoming* call. In one of these calls, I asked the caller to provide me with some information before continuing - I think the payee for a recent transaction (they did give it to me, and she did understand my objection when I explained it!).
In the second call, the other person got nervous, made an excuse and hung up. He was the person who had stolen my wallet from my jacket in my office an hour earlier.
I understand most people giving this kind of information away without thinking too much about it - what I don't understand is institutions making people think it is safe, and the norm.
ASB obviously need to do some work here.
One of my banks gives me a
One of my banks gives me a pocket card reader. After logging in online, if I want to transfer money to a new transferee I insert my debit card and type in my pin, then type in a number displayed on a webpage, the card reader then gives me another number which I then type in online.
http://www.co-operativebank.co.uk/servlet/Satellite/1228376873753,CFSweb/Page/Bank-InternetBanking?WT.mc_id=ask_va_link
Verifying you have the card, the reader & know the PIN
It's an additional step to verify that you have access to the card and reader, and that you know your PIN but PINs themselves fall into one of those secrets that becomes guessable. Many of us use birthdates, shapes on the keypad and other such things which reduce the set of common PINs to a surprisingly small number.
I'm not sure that this adds as much security as Kiwibank does with their approach, and it must certainly add inconvenience. What happens when you're away in another country and your wife is not with you. Do you have two of these? Do you take it with you? Do you defer paying your credit card bill...?
Regards,
Andrew.
A possible mechanism to have your secret secured in the DB
Well, this is what we thought could be done (but what in the end was not implemented because the whole project was stopped) all this using asymmetric encryption, we actually thought about using GnuPG for the encryption parts:
1) DB has password stored encrypted to key A, of which the web application has only the pubkey
2) If the web application needs to verify a secret, it just encrypts the one the user entered
and compares the encrypted strings (just like crypt/md5/sha1 password work on Linux)
3) If a callcenter agent needs to verify the identity of a caller, the following happens:
callcenter software asks agent for the passphrase for his key B (just once per shift)
The software requests the callers secret from an intermediate server, which knows only
pubkey of B and secret key A. The intermediate fetches the encrypted secret, decrypts it
with its secret key A, reencrypts to pubkey B, sends it back to the frontend app, which
just displays some random characters from the secret along with their position in the
secret.
As the webserver doesn't know how to decrypt the secret and the callcenter agent never sees a complete secret, there are "only" two things left you actually have to worry about: The intermediate server and the frontend app. As long as you are sure to control both, the secret will remain, well, secret.
Anyway, a similar approach could possibly help in other situations, so I thought I would mention our preliminary thoughts. We never actually implemented this, as the project was cancelled pretty early.
The way they're doing it in
The way they're doing it in my country, Argentina, is quite interesting:
The matter of "identity verification" is a service provided by companies that pride themselves in having the best available information about everyone. So, when banks and merchants need to verify your identity, they can hire these companies to feel safe and pass the problem on to someone else.
The questions they come up with (from who knows where) are of this kind:
- Where have you shopped recently?
- Which of these companies have you worked for?
- Who of the following people have you worked with in the last 6 months?
- Have you met any of these people? (really)
They offer 4 options + "none of the above".
In all cases, they've provided nothing but obscure names I had never even heard of; so I've chosen the latter and passed all verifications. It's getting ridiculous now.