How to Reduce Payment Fraud

September 22, 2023
September 22, 2023
Reducing Payment Fraud with Reliable Visitor Identification

What is Payment Fraud?

Payment fraud revolves around online financial transactions for goods or services. The keyword is “payment.” This nefarious activity occurs when fraudsters obtain stolen credit, debit, or checking data. Then, that fraudster uses the stolen financial data to make an unauthorized purchase, pretending to be the card or account owner. Often, the criminal will quickly sell the item or items purchased illegally to obtain cash.

Why is Payment Fraud Important?

Payment Fraud is a serious issue for businesses that store, handle, or process payment information. By processing stolen card data, fraudsters can leverage your business for money laundering operations or unauthorized goods/services that will create chargebacks. Chargebacks are when a merchant must return payment for an unauthorized transition and sometimes incur a fee. Chargebacks impact margins, business reputation, customer service, and financial accounting overhead.

Why Fingerprint

Many businesses that have implemented sophisticated anti-fraud systems take into account suspicious flagged purchases based on a visitor's device, IP address, and browser fingerprint. However, despite these measures, some fraudulent purchases still slip through undetected. These companies discover that the accuracy of their current fingerprinting solution is insufficient in identifying all fraudulent activities, leading to chargebacks, lost revenue, and a potential threat to their seller reputation.

After comparing Fingerprint Pro with existing browser identifiers, most people find that Fingerprint Pro's Visitor IDs are unparalleled in accuracy and have far fewer false positives. Our reliable identification signals significantly help our customers improve their credit card anti-fraud workflows.

How to Increase Account Growth by Identifying & Preventing Payment Fraud

Fingerprint Pro provides a unique identifier, known as the visitorId, for every visitor to your website. This identifier is collected behind the scenes whenever someone performs a specific action with our JavaScript fingerprinting agent installed. To ensure data integrity, Fingerprint Pro also offers tools to validate these identifiers sent by your front end. By utilizing these features, you can protect your users and your business from various payment frauds. Additionally, your legitimate users will not experience any additional friction when making payments.

Since you know your product and business landscape best, it is up to you to configure anti-fraud workflows using the visitorId to detect fraud on your website. Below, we provide some steps and best practices that can serve as a starting point for your custom solution.

Configuring Fingerprint Pro for Payment Fraud Prevention

To use Fingerprint Pro effectively to prevent payment frauds such as credit card cracking, chargeback fraud, or stolen card abuse, you should configure logic that utilizes the visitorId among other timestamped data in conjunction with information provided by a user. Therefore, it is crucial to think through the logic used to determine suspicious activity and that the correct actions are taken when a visitor is flagged.

Suspicious Activity Logic

When a visitor attempts to pay for an order, we recommend sending the visitorId and requestId to your application server, where they persist in the storage layer. Using this data, you can compare the current visitorId and credit card pairing to previous attempts to catch threats.

Here are the recommended logic rules for Payment Fraud prevention:

First, you need to add the Fingerprint Pro JavaScript agent to your webpage. Alternatively, if your frontend uses modern frameworks such as React.js or Angular, one can use one of our libraries instead.

// Initialize the agent.
const fpPromise = import("https://fpjscdn.net/v3/<your-public-api-key>").then(
  (FingerprintJS) =>
    FingerprintJS.load({
      endpoint: "https://metrics.yourdomain.com",
    })
);

For production deployments, we recommend routing requests to Fingerprint's APIs through your domain using the endpoint parameter. This prevents ad blockers from disrupting identification requests and improves accuracy. We offer a variety of ways to do this, which you can learn more about in our guide on how to protect your JavaScript agent from ad blockers.

Make a fingerprint request and send the requestId together with the user’s credit card data to your API when they try to make a payment. Note: Sending the user's credit card data in such a way is for demo purposes only! In production, you should be using a more secure method to handle this data and integrate it with the visitor identifiers.

async function onPaymentSubmit() {
  // Collect browser signals and request visitor identification
  // from the Fingerprint API. The response contains a `requestId`.
  const { requestId } = await (await fpPromise).get();

  // Send the user’s credit card data together 
  // with `requestId` to your authentication API.
  const orderData = {
    cardNumber,
    cardCvv,
    cardExpiration,
    requestId,
  };

  const response = await fetch("/api/place-order", {
    method: "POST",
    body: JSON.stringify(orderData),
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
  });
}

All next steps should be performed on the backend using data from the Fingerprint Pro Server API. If your backend logic is built on top of Node.js or any other popular server-side framework or language, you can use one of our Fingerprint Server API SDKs. Alternatively, one can use the Webhooks functionality.

Check that the requestId is legitimate by hitting the Server API /events endpoint.

const requestId = req.body.requestId;

const fingerprintServerApiUrl = new URL(
  `https://api.fpjs.io/events/${requestId}`
);

const requestOptions = {
  method: "GET",
  headers: {
    "Auth-API-Key": "<secret-api-key>",
  },
};

const fingerprintServerApiResponse = await fetch(
  fingerprintServerApiUrl.href,
  requestOptions
);

// If there's something wrong with the provided data,
// the Server API will return a non-2xx response.
// We consider these data unreliable.
if (
  fingerprintServerApiResponse.status < 200 ||
  fingerprintServerApiResponse.status > 299
) {
  // Handle the error internally and refuse the purchase.
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

const requestData = await fingerprintServerApiResponse.json();
const visitorData = requestData?.products?.identification?.data;

The Server API response must contain information about this specific identification request. If not, the request might have been tampered with and we don't trust this identification attempt.

// The returned data must have the expected properties.
if (requestData.error || visitorData?.visitorId == undefined) {
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

An attacker might have acquired a valid request ID via phishing. It's recommended to check the freshness of the identification request to prevent replay attacks.

// Fingerprinting event must be a maximum of 3 seconds old.
if (new Date().getTime() - visitorData.timestamp > 3000) {
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

The Confidence Score reflects the system's degree of certainty that the visitor identifier is correct. If it's lower than the certain threshold, we recommend using an additional way of verification, e.g. 2FA or email.

// The Confidence Score must be of a certain level.
if (visitorData.confidence.score < 0.95) {
  persistPaymentAttempt(req);
  reportSuspiciousActivity(req);
  return getForbiddenReponseAndChallenge();
}

We want to check if the order request comes from the same IP address as the identification request.

// This is an example of obtaining the client's IP address.
// In most cases, it's a good idea to look for the right-most
// external IP address in the list to prevent spoofing.
if (request.headers["x-forwarded-for"].split(",")[0] !== visitorData.ip) {
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

Next, check if the order request comes from a known origin and if the order request's origin corresponds to the origin provided by the Fingerprint Pro Server API. Additionally, one should also set the Request Filtering in the Fingerprint dashboard.

const ourOrigins = ["https://protect-card.yourdomain.com"];

const visitorDataOrigin = new URL(visitorData.url).origin;

// Confirm that the purchase request is from a known origin.
if (
  visitorDataOrigin !== request.headers["origin"] ||
  !ourOrigins.includes(visitorDataOrigin) ||
  !ourOrigins.includes(request.headers["origin"])
) {
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

In real-world applications, we want to prevent chargeback fraud, so next check if this visitor has a chargeback history. Prevent users with chargeback history from placing new orders without further investigation.

// Gets all chargebacks during the last 365 days for the `visitorId`.
const countOfChargebacksForVisitorId = await db.query(
  "SELECT COUNT(*) AS count FROM payment_attempts WHERE visitor_id = ? AND is_chargebacked = 1 AND timestamp > ?",
  [visitorData.visitorId, new Date().getTime() - 365 * 24 * 60 * 60 * 1000]
);

// If the `visitorId` performed more than 1 chargeback during the
// last 1 year, do not process the payment. The count of
// chargebacks and time window might vary.
if (countOfChargebacksForVisitorId.count > 1) {
  persistPaymentAttempt();
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

We typically want to forbid placing orders for users who historically used stolen cards.

// Get all attempts with a stolen credit card for the given `visitorId`.
const stolenCardUsedCount = await db.query(
  "SELECT COUNT(*) AS count FROM payment_attempts WHERE visitor_id = ? AND used_stolen_card = 1",
  [visitorData.visitorId]
);

// If the `visitorId` performed more than 1 payment with a stolen
// card during the last 1 year, do not process the payment.
// The time window duration might vary.
if (stolenCardUsedCount.count > 0) {
  persistPaymentAttempt();
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

Card cracking (also known as carding) occurs when fraudsters attempt to exploit the systems of e-commerce businesses in order to collect credit card information. The fraudsters may already have obtained partial card information or they may be starting from scratch. It is important to prevent users who have a history of using stolen cards, as we did in the previous step, or who try to enter an excessive amount of credit card details from placing orders.

// Gets all unsuccessful attempts for the `visitorId`
// during the last 365 days.
const invalidCardAttemptCountQueryResult = await db.query(
  "SELECT COUNT(*) as count FROM payment_attempts WHERE visitor_id = ? AND timestamp > ? AND check_result != 'Passed'",
  [visitorData.visitorId, new Date().getTime() - 365 * 24 * 60 * 60 * 1000]
);

// If the `visitorId` performed 3 unsuccessful payments during the
// last 365 days, do not process any further payments from them.
// The count of attempts and time window might vary.
if (invalidCardAttemptCountQueryResult.count > 2) {
  persistPaymentAttempt();
  reportSuspiciousActivity(req);
  return getForbiddenReponse();
}

If the above checks have passed, continue with the purchase and store the visitorId for future checks.

Challenge Actions

To prevent fraudsters from making progress with suspicious payment attempts, you can implement additional verification or authentication steps based on your suspicious activity logic. In any of the mentioned cases, we recommend ignoring the payment attempts, notifying the potential account owners about the suspicious activity through email/SMS/phone, or implementing two-factor authentication to challenge the payment attempt in specific scenarios.

Explore Our Payment Fraud Prevention Demo

We have built a Payment Fraud prevention demo to demonstrate the above concepts. Use this demo to see how you can use Fingerprint Pro in conjunction with simple logic rules to protect a payment form. If you want to explore the code, check our interactive Stackblitz demo or open-source GitHub repository. If you have any questions, please feel free to reach out to our support team.

FAQ

What is payment fraud, and how does it occur?

Payment fraud involves unauthorized transactions and financial theft, often through stolen credit card details or identity theft, leading to chargebacks and revenue loss for businesses.

How can you prevent payment fraud?

Implementing multi-factor authentication, monitoring for unusual transaction patterns, and maintaining a blocklist of known fraudulent devices can further reduce payment fraud risks.