Skip to content
Checkout & the First Payment

03.02 · Concept · Free

The Amount Must Never Come From the Browser

Identify every field in a checkout request that the client controls, and move price, plan and identity to the server before an attacker moves them for you.

The player loads only when you ask for it, so this page stays fast.

Curated for this lesson1/2

Checkout & the First Payment

Prevent Business Logic Attacks using Dynamic Instrumentation - Jean-Baptiste Aviat - AppSecUSA 2018

Business logic attack framing directly supports why client-supplied prices, plans, and identities are unsafe.

Also worth watching

Checkout requests are attacker-controlled input, not a source of truth. The browser may express intent, such as a product or plan choice, but price, currency, discounts, tax, quantity limits, account ownership and payer identity must be resolved or authorised on the server before any payment object is created.

What this lesson answers

  • can checkout amount come from the browser
  • which checkout fields must be server controlled
  • why hidden price fields are not safe

Notes

In checkout, the browser is not a trusted place to decide what is being bought, who is buying it, or how much it costs. Anything sent from the client can be edited: hidden inputs, JSON bodies, query parameters, local storage, cookies without server-side validation, and even fields your UI never exposes. The server must treat the checkout request as a proposal, not a fact.

The safe mental model is that the client may only send references and user intent: “I want product sku_123” or “I want to start checkout for plan_pro_monthly.” The server then looks up the authenticated user, the allowed product or plan, the current price, currency, discounts, tax rules, trial eligibility, and account ownership from server-side data. The payment provider should receive amounts and customer identity derived from server-controlled state, not copied from browser-controlled fields.

A common misconception is that users cannot change a field if it is hidden, disabled, generated by React, or validated in frontend code. That is wrong because the attacker does not have to use your UI; they can call the same endpoint with curl, browser devtools, a proxy, or their own script. Frontend validation improves user experience, but backend validation protects money.

After this lesson, you should be able to inspect a checkout request and mark every value as client-controlled unless proven otherwise. Price, plan, quantity limits, discount eligibility, user identity, account id, subscription id, and payment amount should all be recomputed or authorized on the server before creating a payment or subscription.

Common questions

Why is it unsafe to send the payment amount from the frontend?
Anything produced by the browser can be changed before it reaches your API. Hidden form values, JSON properties, query strings and client-side state are all just request data. If the backend accepts an amount from that data, an attacker can submit a lower price while keeping the request otherwise valid.
What should the client send during checkout?
The client should send intent and references, not final commercial facts. For example, it can ask to buy a known product or start a named plan. The server should then load the authenticated user, permitted product, active price, currency, discounts, tax treatment and account ownership from trusted data.
Does frontend validation help prevent checkout tampering?
Frontend validation helps honest users avoid mistakes, but it does not protect the payment flow. Attackers do not need to use your interface. They can send requests directly with their own tools, edit fields in transit, or call internal-looking endpoints with values the UI would never display.