Payment gateway integration: secure your checkout flow
A payment gateway integration hands the card details to a provider, but it does not hand over the trust decisions. Your backend still decides what the order costs, whether it was paid, and when to ship it. The OWASP cheat sheet on third-party payment gateways breaks the flow into five steps and names what goes wrong at each. This guide follows that flow and ends with a one-hour review you can run on a test checkout.
If you would rather have someone outside the team try to cheat your checkout, book a meeting with whitehatstoic: it tests web apps and APIs for weak spots, including sign-in and payments, writes up what it finds with fixes, and retests after you fix them.
What a payment gateway integration still leaves to you
Gateways exist so you do not have to handle card numbers yourself. OWASP notes that they take on sensitive data like cardholder information and reduce your PCI DSS scope, but only if the integration is done correctly. A careless one opens the door to payment spoofing, order manipulation, fraud and business logic flaws.
The reason is simple. The gateway knows whether a card was charged. It does not know what your cart was supposed to cost, which order the payment belongs to, or whether you already shipped it. Those are your rules, and attackers test them.
OWASP describes a typical third-party payment flow in five steps:
- Cart preparation. The user picks items and starts checkout.
- Order initialization. Your backend creates a transaction with the gateway's API and gets back an
order_idor apayment_url. - Redirect to the gateway. The user is sent to the gateway's hosted payment page.
- Payment execution. The user pays, or the payment fails.
- Return and verification. The user comes back to your return URL, and the gateway may also send a server-to-server notification. Your backend checks the result and fulfils the order.

Simplified from the OWASP Secure Integration of Third-Party Payment Gateways Cheat Sheet.
Steps 1, 2 and 5 are where most of the damage happens, because that is where your own code makes decisions. The next sections take them in order.
Build the order on the server, not in the browser
The first risk OWASP lists is price tampering or product substitution through the client. If your checkout page posts a total, a price per item or a discount amount, someone can change it before it reaches your backend. The second risk is the quiet one: a backend that never checks the cart at all.
The fix is to treat everything from the browser as a request, not a fact:
- Accept product IDs and quantities from the client, and look up prices, discounts and stock on the server.
- Validate every product ID, price and discount against your own data.
- Recalculate the total on the server before you create the order with the gateway.
- Store that total and currency with your order, so you can compare against it later.
The stored amount matters for step 5. Without it, you have nothing trusted to check the payment against.
Verify the payment with the gateway before you fulfil
When the user lands back on your site, the return URL often carries parameters such as a status or a transaction reference. OWASP is direct about these: they are untrusted and can be changed. A return URL that says "success" proves only that someone loaded that address.
Before you ship anything, credit an account or mark an order as paid:
- Ask the gateway's API for the payment status from your server.
- Check that the amount, the currency and the order ID match what you stored when you created the order.
- Rely only on server-to-server callbacks, never on the browser redirect, to verify payment and trigger fulfilment.
A payment that went through for the wrong amount, in the wrong currency, or against a different order is not a payment for this order. Treat a mismatch as a failure and log it.
Signed, idempotent callbacks that survive retries
The server-to-server notification is the trusted channel, but only if you can tell it apart from a forgery. OWASP lists four callback risks: trusting unauthenticated or spoofed callbacks, processing orders before the payment status is verified, race conditions when several callbacks arrive at once, and replayed callbacks that trigger repeated fulfilment, such as two shipments or a double account credit.
The mitigations line up with them:
- Check authenticity. Validate each callback, for example with an HMAC signature or a secret token, as your gateway documents it.
- Fulfil once. Make fulfilment idempotent, so an order is processed one time no matter how many callbacks arrive. Keep a lasting record of the events you have handled, so a duplicate is recognised after a restart too.
- Do not drop late events blindly. Gateways retry and can send events out of order. OWASP says to treat checkout expiry separately from signature freshness: verify a late notification and reconcile the current payment state, instead of discarding it only because the checkout expired.
- Log every attempt. Keep a record of each callback for later investigation.
Our post on webhook security goes deeper on signatures and replay, and the OWASP sheet points to its own Webhook Security Cheat Sheet for the same.
Logging and alerts for payment fraud
Good validation still needs monitoring, because fraud attempts and plain bugs both show up first in the logs. OWASP recommends logging every payment attempt, from initiation through redirects to callbacks, with timestamps and IP addresses, and alerting on three patterns:
- An order marked "Paid" with no confirmation from the gateway.
- An unusual number of callback attempts for the same order.
- Payment failures followed by repeated attempts with identical data.
Be careful about what goes into those logs. Record callback identifiers, validation results and the data that ties an event to an order, not raw headers and bodies. Leave out credentials and any personal or payment data you do not need. Never keep card verification codes or PIN data after authorisation, even encrypted, and limit who can read investigation records and how long they are kept. OWASP also suggests fraud and risk scoring during payment to catch carding, where stolen cards are tried one after another. Our post on a logging vocabulary helps you name these events so they are easy to search.
A one-hour payment gateway integration review
Run this on a staging checkout with your gateway's test mode, never with real cards or live orders:
- Cart (15 minutes). Start a checkout with your browser's developer tools open. Change a price, a quantity or a discount in the request. Does the order the gateway receives show your server's total, or the edited one?
- Return URL (10 minutes). Cancel a test payment, then load the return URL by hand with a success status. Is the order still unpaid?
- Verification (10 minutes). Read the fulfilment code. Does it call the gateway's API, and compare amount, currency and order ID with the stored order?
- Callbacks (15 minutes). Send the same signed test notification twice, then once with a wrong signature. You want exactly one fulfilment and one rejected request in the logs.
- Logs (10 minutes). Search the logs from the steps above. Can you follow each attempt, and are raw bodies, credentials and card codes kept out?
Write down each "no" as a ticket. For a broader launch list that also covers sign-in, see our pre-launch security checklist, and for rules attackers bend beyond payments, our post on business logic flaws.
Frequently asked questions
Is a hosted payment page enough to keep checkout secure?
No. A hosted page keeps card details off your servers, but your backend still sets the price, checks the result and fulfils the order, and those steps can be cheated.
Can I trust the success status in the return URL?
No. OWASP treats redirect parameters as untrusted. Confirm the payment with the gateway's API from your server and match the amount, currency and order ID.
How do I stop a payment callback from shipping an order twice?
Make fulfilment idempotent and keep a lasting record of the events you have handled, so a retried or replayed callback finds the order already done.
What should I log for payments?
Each attempt, redirect and callback with time, IP, identifiers and the validation result. Leave out raw bodies, credentials and card verification codes.
Get started
Run the one-hour review on your staging checkout this week. whitehatstoic tests web apps and APIs for weak spots, including sign-in and payments, with a written report and a retest after fixes. Book a meeting with whitehatstoic and tell us about your product, your deadline and your biggest worry; work is scoped after a short call.
Build it right. Test it thoroughly. Keep it safe.
Visit whitehatstoic.com↗


Comments
No comments yet.