March 8, 2017
Online store payment fail
One of the most crucial parts of an online store is without a doubt the processing of payments. Can you believe that some of the largest online stores still screw this part up? ;-)
Two large online stores in Switzerland both shared the same heavy security flaw. They let client-side data interfere with the payment processing - without validating the outcome. I am not going to disclose the name of these online stores, because they have a reputation to loose and this is not why I am writing this article.
Rule #1 of web application security: never trust the client!
Payment service provider (PSP)
The role of a payment service provider is to accept a variety of different payments methods and handle those payments. The online store doesn’t want the risk of processing payments themselves and doesn’t want to bother with PCI DSS (Payment Card Industry Data Security Standards). This is why it makes sense to outsource this task to a payment service provider.
According to the documentation of the payment service provider, there are many ways how you can implement the payment page. (Redirect, lightbox, inline, hidden). The most simple integration is to post the required data to the PSP’s site and let them handle the payment. They then will redirect the customer back to the online store, when the payment was successful or failed. The PSP sends concurrently a separate confirmation request server-side to the online store itself.
Hidden client data
As a software engineer I like to know how data gets from A to B, especially when two different systems are involved. When you select your payment method in the online store and you then get redirected to the page of the payment service provider, some data is sent from A to B. The payment UI already pre-fills your name and the total amount of your cart, which means this data is sent at a minimum. When you view the HTML form in the source code of the online store, you can find some hidden fields that are submitted as well. These contain things like identifiers, external references etc. to make the payment work and to link the payment with the order.
The total amount of the cart is sent from the online store to the payment service provider. The PSP does not know if the cart has items in there for $100 or $25, because it has nothing to do with the checkout of the online store. Now, if you are thinking what I am thinking, yes, you can edit the amount in the form to $1 (or even $0.01) and on the PSP’s page the total amount is displayed accordingly. After the payment was successful the PSP calls the redirect URL of the online store to inform the customer if the payment was successful. The PSP sends parallel a separate confirmation request server-side to the online store with all the information about the transaction, including the amount that was payed. The online store then has to verify this data and then proceed with the shipping procedure.
Incomplete verification
The verification of the amount never took place!!
Both online stores don’t disclose how long this bug persisted and how many bad guys already abused this flaw, but this is heavy. I hope fellow engineers learn form this mistake and won’t build such an epic fail into their applications.
Lessons learned
Even when you think those large online stores must have code reviews, security audits etc. it isn’t always the case. To be fair, the online stores probably relied to much on the PSP, because they handle the payments, which gave them a false sense of security.
Tags: security, payment, e-commerce
« back
About the author
human, software engineer, tech enthusiast, security researcher
E-Mail: blog@cipher.digital
-----BEGIN PGP PUBLIC KEY BLOCK----- Version: OpenPGP (RSA-2048) xsBNBFjAYL4BCACsmBS6zE+0b7mZVtQhmfnRn3+IIQfT6WlE6izM39Q42yxj Hf2GOZU15Xc1x5RM9ZZx7HnMyTQWJMkwCzEba4Ju8dbn8gbFzLFp+mXAWQVJ NOhsLvt58X/k1nQ3HYaYAbJPFE4k89zlFUjBG+a1Qs0kNg5RkaSTcE4iV6L4 749LYRba1VFK1p3eIFmIh1zQnzwFY1WYJjvXHURZel8MA0BJTkmfOW4MRHZL lz8mjmTeWoRyxismRDprEtGynK7oIb3qUKAIr5MtoyESHBhVR+EpWHP0+06T IfOsrsp8maNztXRQRKZxHzNZj/ayGpxBGO19e0/6jNpWGI5Nflwo/oHbABEB AAHNI0RpZ2l0YWxDaXBoZXIgPGJsb2dAY2lwaGVyLmRpZ2l0YWw+wsByBBAB CAAmBQJYwGDQBgsJCAcDAgkQMsB3T2XG/XYEFQgCCgMWAgECGwMCHgEAAOzo B/4obbCU7u4f8kXQiaqAhSCjjyR5ZzdApPCh9i9XJ0qGTULTUuBrin1JDXSj HoiByL2mYh92+I8S+YMWLMiTQzl9O4wx+A0eDnfwbs5jKJSQt5Pc8NMlwWKU pG+R7escZ7le/qJYMgGPUWzFhgaKi8jueMW/NJSmPu/Tu4V9nhyxG9oaV3oP rF+W0bekP84tDJ477clRSSK9ZzjMbLL1PWuNmCd8Gsnd3fyP1WcadIMDrnBB sb+7AQ9eTywJ4Yzogh+cWjwy+TkkfEyCJ0X2n5WPURWc0YOFVqhcV4TYDR4v CHSbh+r7OVKIjqdQKDJwAUCYeSkePbxJYmzRoaTd2+RgzsBNBFjAYL4BCADE i8WrXxZWn42DlKDpnwTFBo/8asY4SJ22Zagkoj3cVvkechDWqQnWD753y5Xo gymfPnNjoQGmClDaQoZ29kC4kHTmBPICHCCLvV/7YVCZC4WPpSnpklbllmk7 S8WTnyEm09gniGyLVy5st6MYmFDB4VnfXpzVYtpyEOyIfGV+JmuT90L872xc +rI1/UuZA15k8M+ViD2xDlBMz3fbWxbt/KEUvbGoh2RW6SBJl1/z33ainQmO oqygZtHhoFybqf/OUAHzASPcy+E4byWBIqwDDumKWfsd1YYkUgPMIxEvNaU3 2Olh5+2HX1y8WAf5cIfXUDfmZ88HmWVVXAK9JjztABEBAAHCwF8EGAEIABMF AljAYNEJEDLAd09lxv12AhsMAACSqQf/Tz5KsfN3Yr82jXeO7jEWqI8yUaV2 vfK2JNfQXMIYDezIPxZU/sOOz9QF5gzHaLzt6moDQzHTZy9IE6q4l5gH1Wcm 1rX2b2b4ST3ThRzuDcfSCDZvUIAQ0WEBlXJZbCMwV8Rs5vsvv/CeXaT19zMb CGD+23A1dKDSDmnlycCSDlTK0dc4flc8qqsMAXXtV7F370L3r76GQGj/ap57 k8K5l8VOqNCU2E8PJ1nU3Kf0fpaPJCpmDp51iZB6Ndx7ujb3qCzt5ND0Nqpz 8wuA9uuzf7LdYsz6MdDo3u8cBYeT2KA2pOA6W1SJgSx62Z4hFZxS5nseW3al tfhqcXA+Ox3+gw== =GS1N -----END PGP PUBLIC KEY BLOCK-----