DEV Community

Cover image for Tutorial: Credit card cracking explained — and how to prevent it
Keshia Rose for Fingerprint

Posted on • Originally published at fingerprint.com

Tutorial: Credit card cracking explained — and how to prevent it

If you see an unexpected surge of small transactions in your online store, you might be excited — you have new customers! However, watch out, as this could well be a type of credit card fraud called card cracking.

Card crackers make small payments that test different expiration dates and security (CVV) codes until they find the ones that work. They do this to discover the correct details for a card.

Credit card cracking, also called card testing, creates additional costs for the merchant due to a chargeback fee for each disputed transaction. If this happens too often, the payment processor may increase their general fees. This is a growing problem: about $18 billion was lost worldwide to credit card fraud in 2014, rising to over $32 billion in 2022.

How can you prevent this from happening on your site? In this tutorial, we will talk through the main layers of defenses you can build against this threat. We will then go through code examples using Fingerprint to better protect an e-commerce site.

What is card cracking?

Card cracking is part of a process in which fraudsters attempt to obtain working credit cards that they can use to make illegal purchases. 

First, they purchase a list of credit card numbers from an illicit source, often on the dark web. These numbers may have been skimmed from physical card readers, exposed in a data breach, or entered online into scam forms. However, these lists may not have the necessary information to successfully make a purchase since you usually need the expiration date, the security code, and sometimes other information, too.

The credit card cracker attempts to make small payments by guessing the missing information. Because the fraudster has a lot of card numbers and a few tries for each card, they eventually will succeed in finding the right combination. Once they have a working card with all the information, they can then go on to make bigger transactions.

Card testing is a similar practice to card cracking. With card testing, the fraudster has the full card information to begin with, and they perform a test payment to verify that the card is still valid.

Impact of credit card cracking

Card cracking affects merchants in many ways, including:

  • Financial losses: Merchants must refund payments from unauthorized transactions made with cracked credit cards and also pay chargeback fees. If the merchant has shipped or delivered anything, that is an additional cost. On top of that, if said merchant has too many chargebacks, the payment provider may punish the merchant with extra fees or less favorable terms.
  • Operational costs: Sellers must investigate and monitor fraudulent transactions, including credit card cracking, to avoid shipping products or providing services when they occur. They also need to decide how to manage or reduce the occurrence of these events. 
  • Reputational damage: For reputable brands, their name appearing on card statements as fraud could result in negative reviews and word of mouth. Additionally, if word gets out that a merchant has allowed card-cracking transactions, this could cause more attempts.

How do card cracking attacks work?

Card cracking needs to be fast. The idea is to test a large number of cards and find the needle in a haystack; that is, a card that works and doesn’t get blocked when attempting to crack it. In addition, as a fraudster, you want to avoid detection. Fraudsters using the same browser and computer with the same IP address run a higher risk of being spotted by even the most basic detection systems.

To test a large number of cards quickly and evade detection, here are some tools crackers use:

  • Automated bots: These will run through lists of credit cards and possible details, testing them out on different sites. Bots run in parallel, taking instructions from a central command for rapid testing and elimination.
  • Device/browser spoofing: When using bots, the card cracker will want to make it look like a human is interacting with the site. One way to appear less bot-like is to spoof (pretend to be) the browser of a legitimate customer. This can be done by automating a real web browser so that the actions, typing, and button clicking are happening on an actual screen.
  • Multiple IPs/VPNs: Sites can block IP addresses, which are network identifiers that provide some idea of who is visiting the site. Card crackers will use a virtual private network (VPN), which lets them switch to different IP addresses as needed to avoid being blocked.
  • Botnets: Computers infected with viruses can be remote-controlled, and a fleet of infected computers is called a botnet. For the cracker, these bots have the advantage of having home internet IP addresses, which are much less likely than VPNs to be blocked.

Ways to detect and prevent card cracking scams

Credit card cracking is a fairly sophisticated technique. Luckily, there are many ways to detect card cracking and fraud in general, including:

Payment processor tools

Many merchants use a payment processor, like Stripe, instead of working directly with Mastercard or Visa. These payment processors often provide tools to help detect credit card cracking and other fraud. One example is Stripe Radar, which uses machine learning to detect fraud and is built into Stripe’s payment services. 

Payment processor tools like Stripe Radar only use financial data to detect fraud and do not look at information about the visitor and their device. Therefore, we recommend pairing them with other strategies in this list, such as device intelligence, to block fraud attempts that the payment processor’s tools may miss.

Card authorization techniques

3DS, or 3D Secure, is a technique that requires additional security verification from a customer. It is a technical standard from Visa and Mastercard that redirects customers to their credit card issuer for authentication. The customer will be asked to provide a password or a one-time code sent to their phone. This is an excellent method to foil card crackers, but unfortunately, it adds additional friction for the user and relies on the issuing bank to implement 3DS, and not all have done so.

Pre-authorization holds

A pre-authorization hold refers to the process where funds are secured from the cardholder but not immediately processed. This is often used in hospitality; for example, when booking a hotel room or a table at a popular restaurant. It can also be used for other kinds of e-commerce purchases (although it is rarer). 

Pre-authorization holds may deter credit card cracking because the cracker needs to wait for the final transaction to complete. However, using a hold is a significant change to the customer experience, so it needs to make sense for the business.

Transaction velocity monitoring

Profitable cracking requires attempting thousands of test payments reasonably quickly. If you’re monitoring usage patterns, this may look like an unusual spike in activity. For example, if a fraudster uses a single account to do this, that merchant can keep track of how many different cards have been successfully or unsuccessfully used in the last 24 hours, 7 days, or longer. The merchant can put that account on hold for manual review if the count is suspiciously high.

Device intelligence and fingerprinting

Device fingerprinting provides a unique identifier for a single device that is hard to change. This device intelligence can detect when a fraudster is using the same device to impersonate multiple people. This is possible because information about the device and its connection is revealed when you visit any website. In addition, device intelligence systems can detect potentially suspicious activity, such as when a virtual machine is being used instead of an actual device.

Fingerprint provides both these capabilities and more via its Identification and Smart Signals solutions. Fingerprint accurately recognizes returning visitors so you can detect repeated use of devices, associate a device with a user or payment, and detect suspicious activity based on a multitude of threat signals.

Fingerprint can also provide the “device ID” / “fingerprint” inputs necessary for Mastercard’s First-Party Trust Program and Visa’s Compelling Evidence 3.0, which are programs that give the merchant a chance to dispute an unfair chargeback.

Tutorial: Use Fingerprint to prevent credit card cracking on your payment portal

In this tutorial, we are going to use Fingerprint to protect an e-commerce site using techniques such as bot detection, rate limits, blocked visitors, and more.

We will assume you are running an e-commerce site and accepting card payments on your site. You may be using Stripe to do this or are directly processing credit card transactions on your systems. 

We will use NodeJS for our examples. (Fingerprint has libraries for all the popular frameworks and languages, and the implementation will be similar in those, too.)

To get started quickly, let’s use some example code from Stripe that simulates some of the code an e-commerce store might have:

git clone https://github.com/stripe-samples/accept-a-payment/
cd custom-payment-flow/server/node
Enter fullscreen mode Exit fullscreen mode

Create a file .env in the root of the custom-payment-flow/server/node folder and add these settings. Optionally, update the appropriate test account values if you have a Stripe account:

# Stripe API keys - see https://stripe.com/docs/development/quickstart#api-keys
STRIPE_PUBLISHABLE_KEY=pk_test...
STRIPE_SECRET_KEY=sk_test...

# Required to verify signatures in the webhook handler.
# See README on how to use the Stripe CLI to test webhooks
STRIPE_WEBHOOK_SECRET=whsec_...

# Path to front-end implementation. Note: PHP has it's own front end implementation.
STATIC_DIR=../../client/html
DOMAIN=http://localhost:4242
Enter fullscreen mode Exit fullscreen mode

Now, run these commands to get the server up and running:

npm install
npm start
Enter fullscreen mode Exit fullscreen mode

You can now browse to http://localhost:4242 to see the example site, which looks like this:

Image of example site for credit card cracking prevention tutorial

Clicking the Card link takes you to a self-hosted payment page, that, at the moment, doesn't do any detection of suspicious activity. Let’s use Fingerprint to try to detect credit card cracking as well as fraud in general.

Using Fingerprint bot detection to detect automated tools

The first layer of protection we will add is Bot Detection. Since bots are used by credit card crackers and not by genuine users, this is a good check to deter credit card crackers. In this example, we will block payments when we detect the user is a bot. 

Install the Fingerprint library:

npm install @fingerprintjs/fingerprintjs-pro-server-api
Enter fullscreen mode Exit fullscreen mode

Sign up for a free trial, and you can then create a secret API key. Armed with this API key, you can now add the following code to the top of server.js, setting the apiKey value with your key:

const {
  FingerprintJsServerApiClient,
  Region,
} = require('@fingerprintjs/fingerprintjs-pro-server-api')

const client = new FingerprintJsServerApiClient({
  apiKey: '<<Private Api Key>>',
  region: Region.Global
})
Enter fullscreen mode Exit fullscreen mode

The bot detection code will be added to the route create-payment-intent. This code is called when the user clicks Pay. We want to run bot detection when this route is called. To do this, we will add code to the front end for Fingerprint to analyze the browser and device, and code in the backend to get a verdict from the Fingerprint Identification service.

In the server, we need to check for the requestId passed from the client, validate this, and determine if Fingerprint thinks this request is a bot:

app.post('/create-payment-intent', async (req, res) => {
  // New code, that takes the requestId from the client, and verifies it with the
  // Fingerprint service, using the bot-detection results:
  const { paymentMethodType, currency, paymentMethodOptions, requestId } = req.body;

  const event = await client.getEvent(requestId);
  const isBot = event.products.botd.data.bot.result != 'notDetected';

  if (isBot) {
    return res.status(400).send({
      error: {
        message: 'Payment failed',
      },
    });


  }

  // Existing code

  // ...
}
Enter fullscreen mode Exit fullscreen mode

There are some changes to the client; first, we need to load the Fingerprint API:

// Load the library immediately, so it is ready by the time the user clicks Pay
const fpPromise = import('https://fpjscdn.net/v3/<<Public Api Key>>')
  .then(FingerprintJS => FingerprintJS.load())

// Existing code

// ...
Enter fullscreen mode Exit fullscreen mode

Note: You need to replace <<Public Api Key>> with your public API key.

When the user clicks Pay, we then send an identification request to Fingerprint using fp.get(). This is for two reasons: First, we need to indicate that the user has taken action and not just visited the page. Second, we need to get a requestId to be used for server validation.

// Using the Fingerprint library, get a requestId for this session

form.addEventListener('submit', async (e) => {
  e.preventDefault();

  const fp = await fpPromise;
  const result = await fp.get();
  const requestId = result.requestId;

  // Existing code

  // ...
Enter fullscreen mode Exit fullscreen mode

Finally, pass the requestId to the server when making the request.

// Include the requestId with data sent up to the server

        body: JSON.stringify({
          currency: 'usd',
          paymentMethodType: 'card',
          requestId: requestId // <-- Add this line
        }),
Enter fullscreen mode Exit fullscreen mode

The requestId is being sent to your server where you can use your secret API key to get the full identification event. This information includes the visitorId as well as the detection result flagging any bot activity. While the visitorId is returned on the client from fp.get(), you should avoid using it directly and use the requestId to get the full event directly from Fingerprint to thwart any client-side tampering. 

You can read more about this here: Protecting from client-side tampering.

Proxying requests to avoid ad blockers

You should also strongly consider proxying requests to Fingerprint through your own domain. This prevents ad blockers from interfering with the operation of the Fingerprint front-end code. We have detailed information on how to do this here: Evading ad blockers with proxy integrations.

Using Fingerprint visitor IDs to enforce rate limits

We can check how many times a visitor has tried to make a transaction (successful or otherwise) in the last 24 hours. If this is above a reasonable threshold, say 5 transactions, then we can block the request or require some other form of verification like a one-time passcode sent via SMS.

Depending on your use case you can tune the limit to fit your needs or enforce a limit only for non-verified users of your site.

To enforce a rate limit, we can record the visitor ID and timestamp for each transaction attempt. Then when the user clicks the Pay button, we check how many transactions have been attempted in the last 24 hours:

// Inside /create-payment-intent handler
// Set up DB connection (using Postgres for this example)
const pgp = require('pg-promise')();
const db = pgp('postgresql://username:password@localhost:5432/database');
const visitorId = event.products.identification.data.visitorId;

// Block requests when more than 5 attempts were made over 24 hours:
let result = await db.any('SELECT COUNT(*) FROM visitor_payment_attempt WHERE visitor_id = $1 AND created_at > NOW() - INTERVAL \'24 HOURS\'', visitorId);

if(result[0].count >= 5) {
  return res.status(400).send({
    error: {
      message: 'Payment failed', // Don't leak specific information about how they were detected
    },
  });
}

const paymentIntent = await stripe.paymentIntents.create(params);

const paymentIntentId = paymentIntent.id;

// Store the attempt:
await db.none('INSERT INTO visitor_payment_attempt (visitor_id, created_at) VALUES($1, $2)', [visitorId, new Date()]);
Enter fullscreen mode Exit fullscreen mode

The credit card cracker’s job is now much harder. They will be blocked after 5 tries in a day and will not be able to test any more cards on your site.

Block known fraudsters with their visitor ID

As seen above, when a visitor clicks the Pay button, we get a payment intent identifier from Stripe. If the visitor then makes a transaction that later becomes a chargeback, Stripe can provide that same payment intent identifier for that chargeback. This alone is somewhat useful, but not enough to identify the fraudster if they try this again.

To solve this using Fingerprint, we can record the visitorId along with the payment intent identifier when a visitor clicks Pay. Later on, when you have a chargeback, you can find out which device and browser was involved and block them, using these steps:

  1. Make a call to Stripe to get the payment intent identifier of a chargeback
  2. Look up the visitorId involved with that payment intent in your database.
  3. Block that visitorId from further transactions on your site.

The code changes we need in our server to store the link between visitorId and payment intent, and check for blocklisted visitors, are as follows:

// Inside /create-payment-intent handler

// ... acquire DB connection ...


const visitorId = event.products.identification.data.visitorId;

// ... other checks ...

// Look up the visitorId from the database against the blacklist, and
// if they are on the list, block them:
let result = await db.any('SELECT * FROM blacklist WHERE visitor_id = $1', visitorId);
if(result.length > 0){
  return res.status(400).send({
    error: {
      message: 'Payment failed', // Don't leak specific information about how they were detected
    },
  });
}

const paymentIntent = await stripe.paymentIntents.create(params);

const paymentIntentId = paymentIntent.id;

// ... other insert statements ...

// Store the paymentIntentId and visitorId for future use and blacklisting:
await db.none('INSERT INTO visitor_payment_intents(visitor_id, payment_intent_id) VALUES($1, $2)', [visitorId, paymentIntentId]);
Enter fullscreen mode Exit fullscreen mode

In addition to recording the payment intent and visitor ID, we can also store their user ID (if logged in), and the email address or physical address they used when making the purchase. We can store information from the Fingerprint API such as IP addresses and geolocation information too.

This data can aid investigations into fraud that may be carried out months after it has occurred.

Key takeaways to prevent credit card cracking

Credit card cracking is an insidious practice that causes a lot of cost and hassle for merchants and credit card companies. 

The best defense is layered, taking advantage of the tools provided by payment providers like Stripe, card authorization, multiple-factor authentication, and device intelligence tools like Fingerprint.

To try Fingerprint now, check out our Getting Started Guide, or contact our team to find out more.

Top comments (0)