Rejecting a PayPal IPN request for security reasons - security

When I get an IPN from PayPal (or a similar service) to indicate a sale, they ask to :
Send back 200 OK
Send back the request body.
As you know the client can easily play with the numbers and set a price of 0, while ordering a product that cost 100$, or just get a spoof message with a fake sale.
In this case, they advice to check the IPN message on the cloud.
But at this stage the sale has been made, and if this was a hack, the seller will have to refund, and this whole scheme sounds wrong.
It seems that i can't really send 400 instead of 200 OK.
I read this How to explicitly reject an IPN request and turn out you can't really reject after you compared the payment request with your DB and found that something was wrong.
So how can i make sure the sale is authentic ?

The best solution is to use a server-side front end UI paired with two routes on your server to 'Set Up Transaction' and 'Capture Transaction'": https://developer.paypal.com/docs/checkout/reference/server-integration/ . Then you do not need IPN at all, for anything.
However, if you are going to use IPN, it is documented here: https://developer.paypal.com/docs/api-basics/notifications/ipn/
There is a verification step where you post the IPN message back to PayPal to check whether it is valid or not. This answers your question.
If what you want to accomplish is refuse the transaction due to an invalid amount or description, at this point it is already too late in the case of a sale type transaction. All you can do is issue a refund via API.

Related

Update my database after Stripe payment successful

I am implementing Stripe on a website for the first time and I'm not sure the right way to do something. After the payment is successful I need to update my database before the client is redirected to the "client's account dashboard", so the dashboard shows the updated information. I thought the right way would be to use webhooks, but if the webhook takes longer to update the database then the redirection, the dashboard will show outdated info.
I found an old post with a similar problem to mine where they said there is no need to use webhooks, as Stripe API calls are synchronous and I can get "the charge object" back which indicates that the payment succeeded. It's a fairly old post so I am not sure if that's the way to go (and also, I can't find information on Stripe Docs on how retrieve the "charge object" once redirected to the "success page")
I would appreciate any help. Thanks!
*Edit: Would polling be a viable way to accomplish this? I can keep the client in the "success page" and use polling to check when the database has been updated, and then redirect.

Can Stripe change the payment intent status between the confirm payment call, if successful, and the webhook they send me?

I have a social app where my customer is going to make single purchases (credits/tokens/likes) using a credit card (Visa, Master, Amex, Discover). When the purchase is complete, and I receive a "succeeded" in the result "status" from the Stripe result, the customer will then be given 10, 20, 50, 100, etc. tokens to their profile that can be used now for "liking" someone.
FYI - If the user has a card saved and chooses that card, that Stripe card number and customer number is used for the payment intent, otherwise I'm collecting the card details, and passing that to the "confirmpayment()".
QUESTION - Once I call Stripe "confirmpayment()" client side, and get the result back, which shows the status (succeeded, failed, incomplete, etc.) Is it possible to receive a "succeeded" status in the result and then at some later date via Stripe's webhook, receive a different status other than "succeeded"?
FYI - I've gone through almost all test card scenarios to test for this type of condition, but it doesn't seem like it will happen? It seems like the payment will either succeed or fail on the confirmpayment() call. I'm also double checking the status result on the server side by fetching the paymentIntent from Stripe. Just to make sure the user (client side) hasn't changed it in the code (JS/Typescript).
Concern - The customer finishes their purchase, the confirmpayment result shows a status of "succeeded", their "tokens" are added to their profile at that moment and then they proceed to use them to send "likes" to another user. Then later on I get the Stripe webhook back showing a different status with "failed" or "incomplete". But by this point, "tokens" will have been used and a monetary amount based on the amount of the "token" will have been moved from my Connect account where the original purchased fund will be sent to the intended receiver's connect account. If this happens I foresee it being extremely difficult to back all this out and reverse it will out a huge headache.
ALTERNATIVE WORKFLOW - I could create a "payment" entity on the server side with a pending status and wait until I receive the Stripe webhook before I add any "tokens" to the user account/profile. This will insure there is no possibility for error, but it makes the user wait until the webhook comes in before they will see a status of "success" on their payment page and won't be able to use any "tokens" from that purchase until I get the webhook. I wanted to give them a more instant experience.
Any help or advice will be much appreciated.
The result you get back after the Promise confirmCardPayment() resolves will be the same as the status you get back on the webhook event so it will never be that a succeeded PaymentIntent transitions back to requires_payment_method or requires_action, as succeeded is an end state of the lifecycle.
Keep in mind, webhook events can be out of order, so technically you could get a payment_intent.requires_action after your payment_intent.succeeded event (if they happen very quickly.
The best thing to do is to fetch the PaymentIntent from the API (after an event) to get the "true" state of the PaymentIntent.

Verify payment is actually completed using UPI (GooglePay specifically)

This is pertaining to the UPI Payment system in India.
I am using the sample code at https://developers.google.com/pay/india/api/android/in-app-payments to initiate Google Pay App to make UPI Payment.
And everything is working fine.
My concern is:
As all this is at the client end (mobile app), a user (say, hacker) may generate random response values and invoke the server URL to tell the server that the payment is successful. How can I prevent that? How can I ensure that the payment was actually made?
In the provided example, there is a query parameter "url", does Google's server call this URL to update the payment status?
I tried, but nothing happened (I created a page which saves the page URL (Request.RawUrl) in a text file, but on payment the page was not called).
May be Google does call this URL (and I missed something), may be it does NOT; can anyone confirm.
Repeat: My actual problem is how to prevent a hacker from fooling the server that the payment is made successfully.
Note: This is to be my first app, so banks are not ready to provide API/UPI integration.
Paytm provides an api to check transaction status, so not a problem with that.
If not a direct solution, any way around will also work as long as it prevents me from manually checking bank statements.
TIA.
We were implementing UPI payment for one of our client and realized same issue.
We haven't tried Secure Intent to solve the issue. As per NPCI Document, Signed content can be passed thru URI but does not know whether response also contains the signed info to verify its been done.. If it works, we have way to make it secure..

Stripe Payment Intents and charge.succeeded webhook sometimes not firing

We create PaymentIntents (with capture_method=manual in case that matters) in our iOS/Android apps when the user places an order.
We send the order to the connected venue once the charge.succeeded webhook fires. If this doesn't happen within a couple of minutes, we expired the placed order on our side.
So interestingly 2 out of 10 times we don't get this webhook to fire.
Im wondering if it's actually wise to listen to this webhook in order to decide if we send the order to the connected account's venue or not or if there is a better way to determine that the payment will actually work once we try to capture it.
Webhooks are the recommended way for getting a payment intent's status, but you can also use the API to get its status.
A quote from the Stripe docs:
It is technically possible to use polling instead of webhooks to
monitor for changes caused by asynchronous operations—repeatedly
retrieving a PaymentIntent so that you can check its status—but this
is markedly less reliable and may pose challenges if used at scale.
Stripe enforces rate limiting on API requests, so exercise caution
should you decide to use polling.
In your case, I'd recommend waiting for the webhook and then after a few minutes, call either the PaymentIntents API or the Charges API if you haven't received the webhook yet.
There's likely something else going on here, so I'd suggest you reach out to Stripe - webhooks should fire all the time, and it's a really really rare occurrence that they wouldn't.

How to react to Stripe PaymentIntent success webhook in frontend

I'm updating a webapp to Stripes SCA ready flow with PaymentIntent.
So far I have working (on my local test server):
Generate Intent on frontend and pass secret to form
Use Elements to collect card into
Use handleCardPayment to create the charge
Now here's the part where I am unsure. The handleCardPayment responses all seem to indicate a succeeded event, but the documentation warns to not use this repsonse, but instead wait for the Webhook response and only then fulfill customer orders.
Step 5: Asynchronously fulfill the customer’s order
You can use the PaymentIntent returned by Stripe.js to provide
immediate feedback to your customers when the payment completes on the
client. However, your integration should not attempt to handle order
fulfillment on the client side because it is possible for customers to
leave the page after payment is complete but before the fulfillment
process initiates. Instead, you will need to handle asynchronous
events in order to be notified and drive fulfillment when the payment
succeeds. Documentation
So far so good, I've set up test webhooks and tunneling through ngrok I can actually receive the paymentIntent from the Stripe webhook.
Now, my question comes at this point, where the Stripe documentation ends. How should I deal with the UI from the point of the "Pay" button being pressed, and how do I in the frontend detect that the webhook has been triggered?
I am wondering if I should poll my own server, which in turn retrieves a database result that indicated if the webhook for this order has been received? Or what is a reasonable way to deal with this, technically and from an UX perspective?
Any pointers?
I just implemented this, and I decided to poll my own server for the update and ask the user to wait. The webhook marks our internal representation as "paid", so we don't need to poll Stripe. If the webhook doesn't come within 30 seconds, we tell the user that it's ok to leave the page, and we'll email them the result.
Technically, these webhooks can take up to 7 days to come in, so that's why Stripe doesn't want you to have the user wait. In reality, it almost always comes in within 5 seconds, and I would rather just have the user wait and see a final confirmation in the same session.

Resources