Skip to content
Payments⏱️ 13 min read·

Server-Side Payment Verification in Nepal: How to Stop Spoofed eSewa and Khalti Transactions

Learn how malicious users spoof client-side eSewa and Khalti redirects in Nepal, and how to implement airtight server-to-server verification, amount checks, and replay prevention in Laravel and Node.js.

Need this wired into a product? See payment gateway integration.

MN
Manoj NeupaneSoftware Developer & Programming Instructor
#Payment Security#Anti-Fraud#eSewa#Khalti#Laravel#Node.js#Web Security
🎯 Who This Tutorial Is For

📋 Prerequisites
  • ✓An active payment integration (eSewa, Khalti, or ConnectIPS)
  • ✓Basic understanding of SQL transactions and state machines

🚀 What You Will Learn & Build

  • ▸How attackers exploit beginner payment tutorials that rely solely on frontend redirects
  • ▸How to query gateway verification endpoints server-to-server with secret keys
  • ▸Preventing cart total manipulation ($10,000 cart paid with NPR 10)
  • ▸Database state machine architecture to prevent duplicate callback replay attacks
1

How Attackers Steal Goods with Spoofed Redirects

Many beginner tutorials in Nepal end with this dangerous pattern: ```javascript // DANGEROUS CODE - DO NOT USE router.get("/payment/success", async (req, res) => { // Attacker simply visits: /payment/success?order_id=105 await Order.update({ id: req.query.order_id }, { status: "PAID" }); res.send("Thank you! Your order has been delivered."); }); ``` Any visitor can open DevTools, copy the success URL, and trigger order fulfillment without spending a single Rupee. ### The 4 Pillars of Secure Payment Verification: 1. **Never trust query parameters:** Never treat `?status=COMPLETE` in the browser URL as proof. 2. **Server-to-Server Lookup:** Your server must initiate an outbound HTTPS request directly to eSewa's status API or Khalti's `/lookup/` endpoint. 3. **Double-Verify the Amount:** Verify that `response.total_amount === order.total_amount`. 4. **Idempotent Transitions:** Ensure orders in state `PAID` cannot be re-triggered by repeated network callbacks.

✨ Expected Output & Verification

A hardened, fraud-proof payment pipeline that rejects spoofed callbacks and alerts administrators to tampered transactions.

🧪 How to Test the Implementation

  1. 1Simulate an attack by visiting your success_url with a fake orderId in an incognito tab
  2. 2Verify that your server rejects the request with 400 Bad Request or unverified status
  3. 3Test legitimate sandbox payment and verify database order transitions atomically to PAID

⚠️ Common Errors & How to Fix Them

❌Ignoring duplicate webhook callbacks

Root Cause: Network retries trigger multiple order fulfillments, sending customers duplicate credits.

Fix: Use database atomic transactions and check if (order.status === 'PAID') return early.

🛡️ Security Considerations & Best Practices

  • !Keep all payment transaction logs in an append-only audit table with timestamps and raw JSON payloads.

❓ Frequently Asked Questions (FAQ)

No, as long as your secret key has never been committed to GitHub or exposed in frontend code. HMAC-SHA256 cannot be reverse-engineered without the secret key.

📌 Summary of Key Takeaways

Frontend redirects are for user experience; server-to-server lookups are for financial truth. Always verify status, amounts, and enforce idempotency.

Official References & Further Reading