Dissecting the Bitcoin Double Spend Attack

Double spend attack

A paper has recently surfaced entitled “Two Bitcoins at the Price of One? Double-Spending Attacks on Fast Payments in Bitcoin” which purports to have successfully crafted fraudulent double-spend transactions. It’s an amazing paper and the vulnerability it discloses is a big deal – it’s also 17 pages long and filled with enough arcane-looking math to make your head spin. This is an extremely important subject to understand since it changes the way merchants should look at unconfirmed Bitcoin transactions and the educated opinions of users will determine how we should move forward. This paper may be an erudite 17 page masterpiece, but useful to the average user it ain’t. Let’s see if we can simplify things, shall we?

Let’s start by defining what it means to “double-spend.” Let’s say we’re in a gold-based economy (wishful thinking, I know) and I’m a scammer. I can go buy a 10 oz gold bar, hollow out 5 oz of gold from the middle, replace it with tungsten and then use the 5 oz I scraped out to create an identical tungsten-filled gold bar. I can then spend both bars as though I had 20 oz of gold, even though I only ever had 10. The definition of a double-spend changes a bit depending on your transaction system, but it basically accounts to spending the same money two or more times.

The way Bitcoin is built, a double spend attack is basically impossible, as long as you wait for the transaction to get into a block – but what if you didn’t? Given that it takes an average of 10 minutes to generate each block, for certain types of transactions it’s not really feasible for the merchant to sit and wait for confirmations before letting you walk away with product. Can you double-spend an unconfirmed transaction? As it turns out you can, and now someone has.

The attack works because of a very simple factor that most folks don’t account for: connectivity. When miners decide which transactions get into a block, they decide based on which transaction reaches them first. Because an attacker could fudge a timestamp with a non-standard client and there’s no central authority (by design) we can’t trust timestamps, so we go by which transaction reaches us first in the case of a conflict. All an attacker has to do is send two simultaneous transactions, one to the merchant and one to an address he controls and make sure that each one reaches its intended target first – easy, right?

Not really. Reaching the miners first is pretty easy, all you need to do there is be more connected than the merchant is. If you’re a Bitcoin scammer, there’s a fair chance you’ve got access to a botnet and can install your own Bitcoin client on thousands of PCs, directly connecting your own client to each of them and making your immediate network absolutely massive. The average merchant probably hasn’t even set up their router properly to get more than 8 connections so beating them on connectivity won’t be hard. The hard part is getting the transaction the merchant wants to see to them first.

Transactions are broadcast indiscriminately, with no client aware of the addresses belonging to the clients it is connected to. This means that your botnet can’t usually target the merchant and force feed them a specific transaction, but there are a few things that increase that likelihood. First, most of the cases for accepting unconfirmed transactions are in-person purchases, so it’s entirely plausible that by sending the vendor’s transaction from somewhere geographically close to them and originating the fraudulent transaction from a more connected but distant client that the mere delay of relaying the transaction could be enough. It’s also plausible that a certain amount of delay could be added between the two transactions, so long as it’s not long enough that the merchant’s transaction can reach the miners first. Finally, if you’re able to compromise the merchant’s network or otherwise gain the IP address of their Bitcoin client, you actually could directly connect to them and send their transaction with zero delay.

Regardless of the methods used to send the conflicting transactions, the result is the same: The merchant sees a 0/unconfirmed transaction, the scammer walks away with product and the merchant’s transaction is invalidated and never gets into a block, allowing the scammer to re-spend those coins.

The silver lining here is twofold:

  1. It’s not 100% effective, so the scammer always risks “losing” his coins to a legitimately completed transaction.
  2. It’s fairly easy to combat and there are even suggested remedies in the paper itself.

One way to beat the scammer here is to be so connected that the cost of being more connected than the merchant is absurdly high. It would also be fairly simple to implement a sort of “listening network” that watches the network for conflicting transactions. Since the conflicting transaction would have to be broadcast at most a few seconds after the legitimate transaction, a wide enough network could catch such instances of fraud before the scammer has a chance to walk away. This “listening network” could even be built into Bitcoin itself, with any node receiving conflicting transactions relaying information about that transaction back through the network, alerting anyone listening for such information.

It’s important to note that while this does represent an unpatched security vulnerability and the researchers were able to perform double-spends in their experiments, there are no known examples of this technique having been used by real scammers yet and all you have to do to protect yourself is wait for confirmations. If you must accept zero-confirmation transactions, make sure you check with some trusted third party source before letting anyone walk away.

No tips yet.
Be the first to tip!

Tip With Bitcoin

1MYZVQYuaDJmBYMxe7rhiCypSVdMf29jAz

Each post gets its own unique Bitcoin address so by tipping you're not only making my continued efforts possible but telling me what you liked. Vote with your (Bitcoin) wallet!

Comments

  1. So what would happen if the merchant was only connected to trusted miners? It would seem that only transactions that have found their way into a block will be reported and the merchant can be sure that the 0-confirmation won't be invalidated by the scammed transaction that must appear later by design.

    • They would still be racing the clock since they can't be connected to every miner. It would narrow the odds but it's still possible that the miner/pool that solves the block will have received the bad TX first AND not be a miner the merchant is connected to.

      Being more connected, especially connected to miners, helps but doesn't eliminate the issue. The real fix is to poll for the conflicting TX at multiple communicating nodes.

    • Anonymous says:

      The miners and pools don't always allow direct connections, and even if they did, there's no knowing by the merchant if the miner or pool ended up rejecting that merchant's transaction such as what would happen if the attacker had already sent to that miner the double spend transaction.

      • Valid point, I'd forgotten that in order to connect to a given miner you'd need to know their IP and most pools don't make a point of publishing their public IPs…

  2. Anonymous says:

    The Finney attack is another double spend merchants need to be concerned about when accepting on 0/unconfirmed. Thankfully that attack is expensive (about $1 per second that the attacker needs to hold a solved block) so the Finney attack is not economically viable against most merchants.

    • Also, to my knowledge no one has yet performed a Finney attack, even as a proof of concept. There's nothing in theory to stop it from happening but it's a lot harder to pull off than this one. The Finney attack can also be mitigated by simply increasing the network hashrate since it relies on solo mining.

Trackbacks

  1. [...] double spend problem is real, but difficult to perform (read more). Ten minutes is all that is required, or about 6 confirmations, to trust a transaction of coins [...]

Leave a Reply

%d bloggers like this: