Securing bank transactions

So, what’s wrong with using hardware tokens for banking? Well, by themselves, they don’t actually protect you. And this is why.

I’m going to discuss this from the viewpoint of European banks, so let’s first run through how internet banking generally works over here.

Your internet banking account allows you to:
- check your account transactions in a list.
- execute a transfer from your account to any other bank account in the world, your own or not
- pay electronic invoices
- direct online pay
- authenticate for government services

Direct online pay: a rarely used feature where you can pay an internet store by being transferred to your bank site at checkout, you authenticate with your token and allow the store to get paid. The actual authentication form is from the bank’s site. (Yes, I see a problem here; great opportunity for MITM.)

Electronic invoices: this is a system where the company in question sends the invoice/bill to the bank *instead of* me and I have to go online to approve the bill so it gets paid. I don’t use this at all and only a few large companies are set up to bill this way. I don’t see the incentive for the user, really.

On top of that, you can have automatic payments of bills, but that requires filling in a paper authorization for each party that is allowed to take money from your account and then wait a couple of weeks until it takes hold. It’s a real hassle, probably intentionally. The only companies I allow automatic withdrawal for is the credit card companies. Note that without this paper authorization there is no method whatsoever for a third party to initiate a transfer of money out of my account. None, period. All other payments are initiated by me.

Government services: you can do a number of transactions with the government using digital signatures here. Like filing tax returns, medical insurance claims, etc. When you request a digital signature key, the government site connects to your bank and the bank checks your credentials using your token, then the government site lets you download a signature key. So the bank is the authentication third party service in this. Once you have the signature key on your machine, you’re good for a year or so.

Ok, so that is the set of services. Now, let’s go through how a session works. Let’s say I’m going to send you money for some reason. This is how it goes:

- I go to the bank’s site, SSL and all, and I check their certificate (yeah, right…)

- they present me with a form containing an 8 digit random number and a field for my person-number (akin to social security nb, except it’s no secret) and a field for the token’s response

- I activate my token with my secret PIN, enter the 8 digit random number, get a 6 digit response back and enter my person-number plus the 6 digit response into the web form, and I’m in. (There’s a time factor, too, so I get 4 minutes to use that particular 8 digit random number).

- I open a payment form, enter your bank account number (or I enter your IBAN and SWIFT, if you have a foreign bank account), the amount, and click “send”. This doesn’t execute the payment, only stores the transaction in a list to be signed.

- Signing: I get another form with the transaction listed and with an 8 digit challenge calculated from your account number and amount, some kind of hash. I activate my token, enter the 8 digit number, get 6 digits back, enter those into the form and click “send”. Off the money goes.

(If I’d entered several payments, all of them would be approved in a single signature. The challenge would have been calculated from all account numbers and amounts.)

- I log out

Ok, next, how do we attack this? Well, assume we get in the middle using DNS poisoning, SSL tricks, address bar tricks or whatever… just assume we can. Then:

- MITM opens the bank’s login page with the random numbers, and displays it to good ol’ Alice

- Alice enters her person-nb and her token’s response to the challenge

- MITM passes the same info back to the bank and is logged in

- Alice enters account nbs and amounts to pay to the MITM

- MITM changes account nbs to his own, increases the amounts and passes this on to the bank

- The bank shows a page with all the requested transactions and the challenge to the MITM

- The MITM changes the account nbs and amount back to what Alice requested and shows the list to her, but does not change the challenge

- Alice signs the challenge and the MITM passes that response back to the bank

- Poor Alice never knew what hit her, she goes shopping for a box to live in

Finally, past the intro, how do we fix this? Well, the weak point is that when the MITM changes the transactions, the challenge that the bank calculates changes, but since it’s just an 8 digit hash code, there is no way Alice can tell that the number wasn’t calculated on the transactions she actually entered. This is the problem.

One bank I work with solves it part ways by having the total amount of all the transactions be a part of the challenge. That at least stops the MITM from stealing more in one session than Alice entered as payments. But it does not hinder the change of destination account numbers at all. So we need to add in the account numbers in the challenge as well, and in a human-readable form. Having them typed into the token would be too much of a hassle.

The only way I see this happening is that the bank produces a list of transactions, including account numbers and amounts, and has the user sign this list using a digital signature of some kind. The list has to be plain ASCII and the application that signs it must be trusted. Using a good ol’ PGP or S/MIME signature on an email, for instance, would be orders of magnitude more secure than the current system and actually would eliminate the MITM threat.

Curiously, the first computer based banking program I used, 12 years ago or so, did exactly this, (except the signature wasn’t PKI based). I created transactions in an offline application, got a challenge, used a token to get a response, all of this resulting in an ASCII message listing the transactions and with the hash and the response, which the app then sent to the bank using dial-up. If you waited a few minutes, then connected again, you got an ASCII based transaction confirmation back, allowing a double-check. But then the internet and the web arrived and it was discontinued.

So in this case, at least, progress isn’t progress at all.

Comments are closed.