Online payment fraud is rampant. Whether it is because it’s easier to steal anonymously, or because tracking down someone over the net and prosecuting them is difficult if not impossible, online fraud hits everyone who takes payments online.

The situation is even more problematic for digital products, in which case credit-card companies or Paypal refuse to provide any kind of seller protection. The reasoning behind it is that digital product fraud does not result in actual material loss, and it’s hard to prove delivery – both are false, but the situation stands as it is anyway.

As a marketplace for digital products, Binpress has been hit by its share of online fraud. We used to accept both Paypal and credit-card payments (through stripe), and both have been abused in various ways.

You can jump directly to the fraud prevention measures if you are already familiar with the fraud methods.

Fraud methods


Paypal promotes itself as a more secure payment method by removing the need to enter credit-card details online. In reality, Paypal account credentials can be compromised just as easily as credit-card details, and it still has the vulnerability of credit-card payments (unless you disable that feature).

Paypal can be abused in several ways, so lets go over the main attack methods:

Paypal account hijacking

By getting a hold of Paypal account credentials or an active logged-in session, an unauthorized user can make payments using Paypal as if he were the real account holder.

This route is very advantageous to the attacker – he does not have to pass all the checks banks employ on credit-card transactions (address, zipcode, CVC) and use the account to pay immediately.

Paypal payments with stolen credit-card details

Paypal allows people without an account to pay directly with a credit-card (unless you specifically disable that option). This means that stolen credit-card details can be used – the same as with every credit-card payment option (which will be covered in more detail in the next section).

Fortunately (or not), Paypal has its own fraud detection mechanism that it uses on credit-card payments. This means that credit-card payments on Paypal are less likely to be stolen, but on the other hand Paypal often rejects legit payments that fail their somewhat strict detection system.

Paypal disputes on legit transactions

In a way, this is the most troublesome fraud of all. The transaction itself will appear completely legit, as the account owner in fact authorized it. What we deal here is “buyer remorse”, where the buyer simply decides he does not want to pay for the transaction, and opens a dispute on Paypal.

Paypal will side with the buyer most of the time, unless you can provide strong evidence of delivery (for example, a sign-off on a shipping paper). To some degree, Paypal will offer payment protection on certain products. Unfortunately, digital goods are not included and Paypal provides no guarantee of protection for those kind of transactions.

Credit-card transactions

Unauthorized transactions

An attacker will attempt to make an online payment by getting a hold of credit-card information. The information can start at only the card number, and extend to expiry date, CVC and even address details.

Unfortunately, confirmation of credit-card details across banks is very inconsistent. Some banks do not even check the expiry date or the CVC security code (!), while others might return a false positive (it would’ve been better if they had returned “not checked”).

To make matters even worse, a bank might approve a transaction even if some of the details were checked and confirmed as incorrect. This attitude extends to some payment gateways, which will leave the decision up to the bank and will not deny a transaction if some of the security checks are false. (We use Stripe by the way, which follows this approach).

Chargebacks on legit transactions

Similar to the Paypal option, a person who paid with a credit-card can later disavow his purchase by filling a chargeback with the credit-card company. This process is worse than Paypal’s disputes, with the cost usually higher and a much lower chance of keeping the money from the transaction.

Fighting back

Recognizing fraud attempts

Before we can stop a fraud attempt, we must be able to recognize it before we process a transaction.

There are some indicators which should be used to detect frauds attempts, with multiple occurring at the same time indicating a higher chance of fraud:

  • The billing country and the IP country (via geolocation) do not match. Advanced attackers will be using a proxy though, more on IPs and proxies later.
  • Usage of a proxy to disguise location and attempt to avoid the previous indicator.
  • IP country (via geolocation) is from a high-risk country.
  • Usage of a free Email service for the provided Email (if you have an Email field in your payment form). Email accounts with private domain names are less likely to be used in a fraud attempt. Again, if the free Email service is from a high risk country, it increases our suspicion of fraud.
  • An unusually large purchase. While by itself is not a real indicator, combined with any other indicator raises the chance of fraud, in addition to the risk of losing more value (in the case of physical goods).
  • High velocity of purchases by the same person – multiple purchases in rapid succession over a short period of time are a good indication of a fraud in progress. The various ways to track a person between transactions are discussed below.

I will now suggest an actual process for getting the information needed for those indicators. You can skip any of the steps, but the more indicators you have the better you can assess the risk of fraud.

1. Check IP

Using the client machine IP, we can attempt to determine the location of the person attempting the transaction via geolocation. In addition to the standard IP headers, proxies might send the actual IP through a long list of alternative headers. See this StackOverflow question for such a list and mock code (in PHP).

Detecting and using a proxy alternative IP header is important for a couple of reasons –

  • First, we have the actual IP to use in the next step – geolocation.
  • Second, using a proxy by itself is a strong indicator of fraud. While not all proxy users are fraudulent users, fraud attempts are much more likely to use a proxy than your average user.

2. Fetching the client address via Geolocation

A geolocation service will receive an IP and send back an approximate address that corresponds to it. You can use a geolocation service via an API or via an IP database on your server. A good free database can be obtained from Maxmind, as well as a more accurate one and an API for a small cost.

Once we have the client IP from the previous step, we use our preferred method to fetch his/hers location through our geolocation service.

3. Compare client address to billing address

The rule of thumb is simple – the farther away the client current location is from his billing address, the higher chance we’re dealing with a fraud transaction. The chance of fraud increases even more when the location is confirmed from a set of high-risk countries (mentioned above in the list of indicators).

The billing address should be collected on the payment form for credit-card transactions, or via GetExpressCheckoutDetails API operation for Paypal transactions, before confirming the transaction (if you use the “Buy Now” buttons instead of the API, you’re out of luck. Consider switching to the API – we have a great Paypal API component for PHP that makes using it very simple).

Of course, an address mismatch by itself is no confirmation of fraud. People travel all the time to different countries and use their credit-cards to make payments online. We should use this information with the other indicators to assess the risk of fraud.

4. Check Email address

Note: this step is only applicable if you collect an Email address in your payment form, or use the Paypal API which provides it in the billing details.

As mentioned before, free Email services are much more likely to be used in a transaction – and especially if the Email service is a fringe, lesser known service. There is quite a comprehensive list over at Yahoo, and you should add the domains of each to the check you run on the provided Email address.

If the Email address is from a free service, we should take it into account as another indicator with the others covered so far.

5. Consider size of transaction

Larger transactions are more likely to be fraud than smaller transactions. When we have hit several indicators already, the size of the transaction should be used to downgrade or upgrade the chance of possible fraud.

In addition, calculate the possible losses according to the size of the transaction (especially if dealing with physical goods), and use it to lower or raise the bar for which a transaction might be flagged as a possible fraud.

6. Review bank credit-card checks (credit-card transactions only)

This step does not apply to Paypal transactions as they run their own fraud detection system and do not provide such information before completing the transaction.

Most payment gateways will allow you to receive the results of the checks the bank runs on a credit card before completing a transaction.

For Stripe users - If you use Stripe, like us, you might not realize they do provide this option, though not directly. You can get the results of the bank credit-card checks by creating a customer with the payment token before actually processing the transaction, and then deleting the customer once the transaction has been processed. Ideally, they would have provided this information when the token is created, but currently they do not.

The fields banks can validate aside from the actual card number include the Zipcode, CVC security code (found on the back of the card), street address and expiry date. Different banks run different checks, and you might decide to reject a specific card on the grounds that his bank does not provide enough security information (such as not validating the CVC or expiry date).

I personally consider CVC, Zipcode and expiry date mismatches as showstoppers. Those are details that cannot be incorrect, while the address field is a bit harder to validate (everyone writes addresses a bit differently, and it’s also hard to correctly write down foreign street names in English).

Making a mistake on any of those does not necessarily indicate fraud, but should stop the transaction. Making multiple mistakes in rapid succession though is a good indication of a fraud attempt.

7. Check the logs

I will cover the actual logging of the transaction in the next step, but before we get there in the actual process, we want to check our logs for suspicious behavior. Suspicious behavior might include:

  • Multiple transactions in a very short time by the same person
  • Multiple failures over a longer time period by the same person
  • Whether the person was previously flagged as fraud (by IP or session ID – see next step)

The amount of transactions and time frame that should trigger a fraud alert is up to you. You can attempt to gather that information by reviewing the logs after several frauds have taken place, or by attempting to guesstimate numbers that make sense to you.

8a. Suspected fraud – log the attempt and deny the transaction

With all the data we have accumulated thus far, we have decided we have a possible fraud in progress. At this point, we will show a message to the user, and log the transaction attempt for future reference (and for step 7).

Details we want to store:

  • Client IP
  • Proxy IP (if we found one)
  • Country (and city optionally)
  • Client user agent
  • Client session ID (if you are using sessions – which you should, for this purpose at least)
  • Transaction attempt date/time (timestamp)
  • Other identifying details relevant to your service (such as user identifier if you have it)
  • Transaction status (failed in this case)

Why do we store both IP and session ID? while both can be changed between transaction attempts, they can be considered as failsafes for each other. Our attacker might switch to another proxy but still use the same browser for example. It doesn’t hurt to have as many data points as possible.

The message we will show the user at this point depends on your philosophy – I suggest not mentioning “fraud” as the reason as you might scare away potential clients as well as alert the attackers that they’ve been caught. You can say the card was rejected by the bank (in the case of a credit card transaction), or that Paypal has rejected the payment. I leave the actual wording up to you.

Optionally, you might choose to manually review suspected transactions. In this case you should show a message indicating the transaction in under review and the time-frame for completion. If you do choose to manually review transactions, remember to save all the details you’ll need to complete it later, such as payment tokens or even credit-card details if you know what you’re doing (if you’re not PCI certified, I’d highly recommend against it).

In extreme cases (close to 100% certainty of fraud), we might go as far as block the payment form for the IP / session ID of the attacker, and at this point we will show a message mentioning “suspicious behavior” so that legit clients can contact us and notify us that they are not in fact attempting fraud (this has happened for us once at Binpress, and the verification process wasn’t that simple).

8b. Log and process the transaction

If we made it this far and have not reached our threshold for determining a fraud is in progress, we will try to process the transaction. Regardless of whether it was successful or not (rejected by the bank or the payment gateway), we will store it in our log for future reference (and for detecting a high volume of purchases by the same person).

The case of Paypal

We’ve mentioned one attack pattern that we haven’t fully addressed yet – usage of an hijacked Paypal account to make a payment.

While the same indicators apply, we have an additional option to confirm legit account ownership – by verifying the Paypal account Email address.

The Email address (and billing country used for one of the indicators), can be obtained before confirming the purchase via the GetExpressCheckoutDetails API operation (assuming you use the API. If you use the Buy Now buttons, you are out of luck).

This means implementing a process similar to the following:

  • On the Paypal confirmation page (after user has confirmed payment in their Paypal account), we check for any of the previous indicators by getting the account details with the GetExpressCheckoutDetails API method and examining the user IP.
  • If we suspect the account might be compromised, or the purchase is large enough to require more caution, we send a confirmation Email to the account Email address with a unique identifier (usually in a link back to our site). We save the identifier and Paypal payment details in our database or in the session.
  • If the user opens the confirmation Email (meaning he has access to the account Email) and returns to our site with the identifier, we confirm the transaction and finish processing the payment.

Obviously, if the attacker has control of the account Email as well, he can easily bypass this method as well. If the indicators are very strong, we might consider holding such transactions for manual approval.

Note that you cannot change a Paypal account primary Email without entering one of the complete payment details (such as a credit-card or bank account numbers). Any change or addition of Email accounts to a Paypal account will notify the original Email account as well.

Something worth mentioning is that you cannot distinguish payments with a Paypal account from payments using a credit-card through the information returned by the API. This is a problem in the sense that there is no point in sending a confirmation Email to someone who used a credit-card to pay, as the Email given is the one he entered at payment (meaning he would likely have access to it).

The only indicator between a Paypal account payment and a credit-card payment is the ‘PAYERSTATUS’ parameter in the billing details returned by the GetExpressCheckoutDetails API method. A ‘Verified’ status indicates that is a Paypal account payment, while an ‘unverified’ status can be either. For this reason, we only send the verification Email to accounts that are verified, while we use more caution with ‘unverified’ accounts.

You might even consider rejecting ‘unverified’ accounts outright, just keep in mind that you won’t be able to receive credit-card payments through Paypal if you do.

Buyers remorse

The trickiest type of fraud to handle. If possible, always try to obtain proof that the user has made the transaction himself. If you ship physical goods, obtain proof of successful shipment.

For digital goods you can use try to ask for an authorization Email or a declaration of purchase (using digital signature services). Naturally, this process it not appropriate for most websites, and in that case you will most likely have to swallow the fraud as a loss.

Another factor is the originating country (if you serve an international audience). High risk countries are more likely to fall to this kind of fraud as well, which is one of the reasons many services do not accept payments from such countries.

Fraud detection services

If all of what I’ve described so far sounds like a pain, it’s because it is. If possible, I would suggest passing this information to a proven fraud detection service, and rely on their experience and expertise to increase your fraud prevention success.

A fraud detection service might be provided by your payment gateway. If not, or if you are not satisfied with it, I personally recommend the Maxmind Minfraud service. You might have noticed I’ve mentioned 2 Maxmind services here – and it’s not by accident (and no, it’s not because I was paid to promote them :) ).

The Minfraud service receives the information we collected thus far and provides a risk score and other data for our assessment. They use their own geolocation service to determine the location of the client (we pass them IP addresses we found), and in addition, they have a database of known proxy IPs that can be used to determine when a proxy is being used and how dangerous it is (how prone it is to be used in fraud attempts).

They use that data to compare with historical data they collected on online fraud to calculate the risk score – which is basically the chance the transaction is a fraud attempt (in percentage points).

The reason I’m advocating Maxmind so much, is that since adding Minfraud to to our payment process, we have not had one fraud slip through their checks (and we had quite a few attempts). We use it in a combination with logging and the bank security checks review to very good effect.

Bag it and tag it

So there you have it – a basic guide to knowing, detecting and preventing the most common types of online fraud. If you feel I missed something or have a question regarding something I wrote, feel free to add your thoughts in the comments.

Posted in Binpress