Not every day can you apply lessons from Second World War cryptanalysis to your own web applications. But today, that’s exactly what we’re going to do. In fact, we’ll take a look at how even one of the most powerful modern cryptographic tools can be defeated by the same method that Alan Turing used to break the Enigma machine—which was the most powerful cryptographic tool of its time—if the implementers make the same mistakes in message transmission that Turing found.
Let’s take a look at an API that I assessed recently, to see how it avoided the problem that helped the Allies beat the Axis powers in World War II.
An eCommerce API: A pretty sweet pot of honey
The example I’m going to take a look at today is an eCommerce company’s API for accepting payment. As far as attack targets go, there aren’t many more valuable for malicious actors to go after than a credit card payment API. That’s why this company decided to expose a public key to the world by which API consumers could encrypt all credit card information being submitted for payment processing.
That’s right, all of the data submitted by this form would be encrypted and never sent in plain text. This is because it’s important to guard all of the data here against attack, not just the card number. The expiration date and CVV are part of the package that makes any particular payment method unique, so this company had it all encrypted. The company would never send any of it in plain text.
Here’s how a sample request looked as it came across the wire, using a Charles Proxy to capture the traffic as a man-in-the-middle:
Notice in this example that there are two hashed values coming across: paymentHash and cvvHash. Let’s think about the data that’s contained in these two values.
For paymentHash, we have the 16-digit credit card number, encrypted using the public key published for use on this API. Obviously, there will be a lot of variation in the values available going into the encryption.
For cvvHash, we don’t have the same situation at all! CVVs are only 3 digits. If you only encrypt three digit combinations, then an attacker could build up a complete dictionary of only 1,000 different values (10 values for each of the 3 digits). With that dictionary, they can find the CVV of any card sent across this API. Fortunately, my customer knew how to avoid known plain-text attacks and had already implemented randomized padding to avoid the same attack that brought down the Nazis.
Cracking the Enigma
In part, the Enigma machine was so hard to crack because it had a very complex structure for encrypting messages and the settings were frequently changed. However, since the machine was used for military messages, Turing’s team at Bletchley Park began searching for text that could be expected in many of the messages.
One type of message that was frequently sent by the German military was a weather report, and these reports included the German word for “weather” in the same place in every message, followed by the known weather conditions. Another example was that many messages ended with “Heil Hitler” and some operators used standard salutations. These instances also made it possible to determine some of the plain text and settings for each day.
This type of encryption vulnerability is what could have been present had this eCommerce company not used randomized padding for the CVV, because the number of possible values is so small.
Avoiding the same mistake
By using a random pad, the company ensured that two payment methods with the same CVV would not reveal anything about what was being transmitted. Here are a few examples of the same value of “777” could be encrypted to have different values by using a pad:
$ echo -n 777 | openssl rsautl -inkey public_key.pem -pubin -pkcs |
As you can see, the commands run above are all the same, but due to the standards in place in RSA encryption, the values that are output are all completely different.
Good encryption algorithms are not enough
This example should help you understand that it’s not enough just to put a good encryption scheme in place. Even with highly sophisticated encryption algorithms, if the same input is used over and over again, it’s possible that this will expose the data you are trying to transmit securely. It’s very important—especially when dealing with payment information—to make sure that it’s not easy to guess the values being sent across the wire.
Another example where padding matters is password storage. Developers know they need to use a good one-way hash function to make sure that even they can’t read the passwords their users are submitting. For this, developers should add a random string (called a salt) to any password before hashing it.
Conclusion
Building security into your web applications is a hugely important task. Making sure your users’ sensitive data is not easily decrypted builds customer trust and ensures the longevity of your business. After all, no one wants the media coverage that their site leaked customers’ payment information. If you are able to make sure you don’t encrypt the exact same values over and over again, you’ll avoid a very basic error and also keep your customers’ data safe.
For more on security best practices, check out Linode’s extensive set of security guides!
Comments