Yesterday, for the first time in the seven-year history of our OPLF shopping cart, somebody used our shopping cart for “card testing”. A fraudster in a foreign country had purchased a bundle of stolen credit card numbers, and wanted to determine which of the cards was still valid. Such a person will engage in “card testing”. The person tries to make purchases with the credit card numbers, using an online commerce site. Yesterday, the person chose our OPLF shopping cart. By the time that we had shut out the “card testing”, the fraudster had tested about 198 credit card numbers, and had found two of the cards to be valid. (This means the card holder had not yet canceled the stolen card number.)
How did we learn that the “card testing” was happening? What did we do in response? What permanent harm, if any, flowed from this incident? What protective step might we have taken earlier?
I will provide a bit of background on the way that we constructed our OPLF shopping cart some seven years ago. The starting point was a cPanel hosting platform which we got from Namecheap. Using the cPanel, we installed a number of systems including instances of the web hosting platform called WordPress. Using the one of the instances of WordPress, we installed a shopping cart system called WooCommerce. We set up a merchant account with a credit card proccessor called Stripe.
What things cost? The cPanel hosting from Namecheap costs about $109 per year. WordPress is, remarkably, free and open-source. WooCommerce, too, is free and open-source. The open-source nature of WordPress and WooCommerce (and of the many related plug-ins) means that the software is of higher quality than closed-source private software packages.
Before Stripe came into existence, credit card processing for e-commerce entailed up-front costs and monthly costs. Pricing for credit card transaction commissions was opaque and expensive. Stripe imposes no up-front cost and no monthly charges, and the commissions are transparent and inexpensive.
API keys. One way to use Stripe is by means of an “API integration”, and this is how WooCommerce uses Stripe. The WooCommerce shopping cart passes messages back and forth to Stripe using an application programming interface (API) and using public-key cryptography. Public-key cryptography uses a pair of cryptographic keys, one of which is the “private API key” and the other of which is the “public API key”. When we signed up with Stripe about seven years ago, we clicked around in Stripe to create the two keys, and we copied them into the WooCommerce system. An eavesdropper listening in on the messages that go back and forth between our shopping cart and the Stripe system would not be able to make any sense of the messages because they are encrypted from end to end by means of the API keys.
And so our shopping cart has functioned, requiring very little attention, for the past seven years. Nobody has ever tried to use a stolen credit card. Nobody has ever disputed a credit card charge. We have fulfilled tens of thousands of uneventful orders for webinar registrations and sales of books and the like.
Until yesterday, when this email message arrived from our credit card processor, Stripe:
We then logged in at the shopping cart system and were astonished to see dozens of failed orders.
Somebody in a foreign country was visiting our shopping cart over and over again. Each visit presented a different credit card number than the previous visit, and used a different IP address than the previous visit. It would have been impossible for us to fulfill any order because the shipping address was not a real address.
Although most of the orders failed, two orders actually succeeded in the sense that the credit card payment went through.
What we quickly figured out was that this person was doing “card testing”, which is also sometimes called “carding” or “account testing” or “card checking”. Card testing is a type of fraudulent activity where someone tries to determine whether stolen card information is valid so that they can use it to make purchases.
As you may appreciate, it was only a matter of time before we would have caught on that this card testing was going on. Sooner or later we would have noticed dozens of failed orders in our shopping cart system. But what really happened is that Stripe sent that email message (quoted above) to us. Stripe is very smart about all of this, and they monitor payments across their entire network in real time in their system called “Radar”. They block high-risk payments like what we are talking about here. And, importantly, they send an email message to warn us about it. And the email message had a link to a very helpful knowledge-base page that you can see here. WooCommerce has a similar very helpful knowledge-base page that you can see here, including a concise and clear quick-response checklist.
Our first step was to refund the two credit card payments that had worked. It was clear from context that the two credit card numbers had been stolen and that the owners of the cards had not yet reported the card numbers to be stolen. But sooner or later the owners would figure out that their cards were stolen and would (quite reasonably) dispute the payments to us. So we immediately refunded the two payments.
Our next step was to “roll the API keys”. This is geek-speak for disabling our existing public and private API keys, and creating and installing new public and private API keys. I am delighted to be able to report that Stripe makes it very easy to disable the old keys and to create new keys. And I am delighted to be able to report that the WooCommerce system makes it very easy to delete the old keys and to load in the new keys.
The idea here was that we had no choice but to consider the possibility, however small, that somehow our private API key had fallen into the wrong hands. This seemed most unlikely for several reasons but we had to consider it. So we “rolled the API keys”.
We then went back to the purchase log at Stripe to see if the rolling of the API keys had caused the card testing to cease. And it did not cease. We went back to our order processing system to see if the failed orders were still arriving. And indeed they were still arriving. This told us that the fraudster was probably not in possession of our private API key, but was simply continuing to make use of the (newly created) private API key that was we had just now installed in the bowels of our shopping cart system.
And indeed if the fraudster (or anybody else in the world) had somehow been in possession of our private API key, that would cease to be a concern given that we had just gotten done “rolling the API keys”.
Our next step was to install a “captcha” in the “purchase” button on our shopping cart. This, it turns out, is easy to do. Did I mention that both Stripe and Woo provide very helpful knowledge base articles about all of this? It took only about five minutes and maybe twenty mouse clicks to install the captcha.
I will hasten to reassure the reader that the captcha that we installed is not the extremely annoying sort of captcha that we all dislike — the kind that shows an array of twelve grainy photographs of sidewalk pavement and challenges the user to click on the ones that have dog poop on the sidewalk.
No, this one is an “invisible” captcha, for which (in most cases) no user interaction is required at all. Similar to the “I’m not a robot” captcha which merely asks the web site visitor to check a box, the software of the invisible captcha analyzes the user’s activity like typing patterns, mouse movements, and browsing history. In most cases the software concludes that the web site visitor is legitimate and the user is permitted to continue clicking (in our case, the user is permitted to finish the credit card purchase). If the software is unsure, then it will challenge the web site visitor to click on the images that show dog poop.
And indeed, mere seconds later, the card checking ceased.
The alert reader will, of course, want to see this “invisible captcha” in action. The way to do it is to go to our shopping cart and place an order. (I recommend purchasing Oppedahl on PCT Forms and PCT Docketing which is the ideal companion for the upcoming four free-of-charge webinars on inbound Patent Cooperation Treaty forms. Yes, I know what you are thinking. You are thinking that this sounds like a fascinating topic, and that no one anywhere would ever characterize this subject matter as “dry as toast”. In fact by now you have probably already registered for the four webinars and have forwarded the information to friends and colleagues because you know they are enthusiastic users of the Patent Cooperation Treaty.) When you are on the page to click to finish the purchase, do a “view source”. You will see these two lines tucked away inside the HTML code for this web page.
These lines of code trigger the invisible captcha.
Which brings us back around to the questions presented at the beginning of this blog article. How did we learn that the “card testing” was happening? What did we do in response? What permanent harm, if any, flowed from this incident? What protective step might we have taken earlier?
How did we learn that the “card testing” was happening? As discussed above, we learned about the card testing from a “Radar” warning from Stripe. (Did I already mention that the service provider Stripe performed admirably in this incident?) If that warning had not arrived, we would eventually have caught on to the problem because of the large number of failed orders in our shopping cart system.
What did we do in response? As discussed above, with the help of the quick response checklist provided by Woo, we did three things:
- we refunded the fraudulent payments;
- we rolled the API keys; and
- we installed an invisible captcha at the shopping cart system.
(Did I already mention that the service provider Woo performed admirably in this incident?)
What permanent harm, if any, flowed from this incident? From our point of view, the only permanent harm is possible damage to the reputation of our business with card issuers and card networks, because of the declined charges, which makes all of our transactions appear riskier. Fortunately we were able to cut off the card testing within minutes of its start, after only about 198 tests. My best guess is that this small number of transactions will be lost in the noise level for transaction processing, and that we won’t suffer significant damage to our reputation with card issuers and card networks.
What protective step might we have taken earlier? It is clear, in retrospect, that if we had only installed the captcha earlier, this incident would almost certainly have never occurred.