Is it possible to implement CAPTCHA with Stripe Elements?

Viewed 148

We've currently got Stripe Elements set up on our Next.js website. It's a donation form where users can make a simple one-off payment as a guest.

Here is how the 'submit' method of the form is implemented:

export const makeOneOffPayment = async (
  e,
  stripe,
  elements,
  clientSecret,
  setError,
  billingInfo,
  paymentAmount,
  paymentIntentId,
  CardNumberElement,
): Promise<boolean> => {
  // Initialise
  e.preventDefault();

  // Update the payment intent
  try {
    const res = await fetch('/api/payment-intent/update', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        amount: paymentAmount * 100,
        paymentIntentId: paymentIntentId,
      }),
    });

    if (!(res.status >= 200 && res.status <= 299)) {
      const result = await res.json();
      const message = result.message;
      setError(`Payment failed: ${message}`);
      return false;
    }
  } catch (err) {
    setError(`Process failure on client`);
    return false;
  }

  // Finish the payment
  try {
    const payload = await stripe.confirmCardPayment(clientSecret, {
      payment_method: {
        card: elements.getElement(CardNumberElement),
        billing_details: {
          address: {
            city: billingInfo.city || '',
            line1: billingInfo.AddressLine1 || '',
            line2: billingInfo.AddressLine2 || '',
          },
          email: billingInfo.email,
          name: billingInfo.name,
          phone: billingInfo.phone,
        },
      },
    });
    if (payload.error) {
      setError(`Payment failed ${payload.error.message}`);
    } else {
      return true;
    }
  } catch (err) {
    setError(`Process failure on client`);
    return false;
  }
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

It's a simple payment flow that works, but we're having a problem - people are 'card testing' using our form.

According to Stripe's documentation here, a captcha should be used to prevent this.

The problem is that this code is executing on the front end.

Stripe support has suggested that we add Google ReCAPTCHA verification at the beginning of the 'Finish the payment' try-catch block, then use the result to determine whether to try and complete the card payment.

But how can we be sure that the result from the ReCAPTCHA verification is genuine? I can imagine it's pretty easy for the attackers to spoof a response since all of the logic is running on the front end?

Is there any way for me to successfully integrate a captcha with the current processing flow?

The approach I can think of that would work is to move the logic to an API route, then verify the captcha and process the payment on the back end. But I believe the stripe.confirmCardPayment is designed to run on the front end (and it helps with 3D card verification), so I'd have some different challenges to overcome with this approach.

1 Answers

You would want to add a captcha prior to exposing the checkout form. Take a look at this video. You could also add the invisible reCaptcha to only show when suspicious behavior is detected.

Related