Is Moneris Direct Post Secure? - security

I am looking at the Moneris Payment Processing and their Direct Post method. For the life of me, I can't figure out how the security on it works.
As best as I can tell it does this:
Web User comes to my site. They fill out their credit card information (https).
I show them a summary in a form. When they hit submit they go to Moneris (POST) - including my ID, credit card info, and a custom Transaction ID.
Moneris processes the transaction and sends them back to my site (as a POST)
If they arrive on failed.php or whatever URL you specify, the transaction failed. Else:
If they arrive on gotyourmoney.php then the transaction seemingly worked. Time to validate. (included in POST vars is a Unique ID for the transaction, date/time stamps, response_code (got money, didn't get money) and a few other miscellaneous items.
I redirect the user back to the moneris site with another POST. I include my ID again and the Unique ID returned in step 5 to verify the transaction.
User is redirected back to gotyourmoney_verified.php as a POST again with the unique ID, Transaction ID, and response_code.
What I can't figure out is this:
No where does there seem to be any information that I can validate that the web user can't just make up. Even though it is an https connection I'm trusting the user to pass all information. They could immediately go to the gotyourmoney.php page and never even go to the moneris payment gateway. They can just make up the ID's. When I send them back to moneris for the transaction verification, again they could just post a made-up response to my site.
What am I missing?

The Transaction Verification feature of DirectPost can be used to prevent spoofing.
Here's how it works
A customer enters their credit card information on your site and the information is sent to Moneris for processing
Moneris processes the transaction and sends the transaction result to your site
If transaction verification is enabled then there will be a special field in the transaction result called a "transaction key"
Then to verify that the transaction wasn't spoofed, your site would send the transaction key in a transaction verification request to Moneris
Moneris would then verify the transaction using the transaction key and respond with a result that lets you know if the transaction was spoofed
The Integration Guide for DirectPost has all the details on how to implement the Transaction Verification feature and can be download at http://developer.moneris.com (free registration required).
In addition to Transaction Verification you can also setup a referrer URL. If a referrer URL is setup then Moneris will verify if the transaction is coming from an allowed URL. It's possible to circumvent the referrer URL feature but having a referrer URL enabled is still useful as part of a defense in depth strategy because it makes it that much harder to spoof a transaction.

Indeed since all of those things go through the client, they can easily be spoofed. And the Moneris documentation doesn't tell you this. You need some sort of server-to-server step to be sure that everything is in order.
I would suggest doing a preauthorization using the hosted pay page and then doing a capture with the PHP API. Since you're doing the capture server-to-server, any attempt to spoof by the client will just result in a failed capture.

Related

Protecting POST route without password possible?

Noob here working on first backend project.
What I’m trying to do...
Collect member data via my form (name, email)
User clicks paypal button to pay for membership
When payment approved by paypal, send post request with form data to my members endpoint to add new member
I now realize if I use postman to post to my members endpoint it works. So a malicious user could post data to my members endpoint regardless of paypals payment approval.
My understanding so far is that if my server allows CORS and I don’t password verify the user, anyone can post to that endpoint.
Is it possible to allow post requests only after payment approval without the use of a password?
I’m thinking of online stores that let you checkout without a password. How do they post the collected form data to their db without jeopardizing their post route?
Hope this wasn’t too vague. Pointers would be greatly appreciated!
I’m using node/express, but since it’s a general question I assume it doesn’t really matter..
These answers helped but still didn’t get me there.
Protecting post routes NodeJS
Can I only accept traffic from certain requesting domains with Expressjs?
So post / get request in general are functions of the browser and or server, I can create a simple html form and post to any URL I want to.. Now the question is, will it accept it or not.
When communicating between servers and web-services unless open to the public will use token based authentication to validate the request. So in terms of paypal, the typical flow would be.
(note, very oversimplification below and is just a sample of one such pattern)
User clicks paypal button from your site ( this will contain some type of paypal ID of sorts )
User is directed to paypal and after completing the transaction paypal redirects users back to your server with a token
your server reads the token ( sends API call to paypal with token to verify its valid, if success then process the post )
You can't prevent a user from posting data to a URL, however you can tell the server what to do if they do. So protecting your route from unauthorized post can be handled by sessions, tokens etc. For example, if you have a route on your server, lets call it user profile. This route first executes a check for the session, if its there keep processing, if its not, redirect the user.. Its really no different for callbacks / token auth.
Essentially, you will need to handle what the server does in your code because anyone can post to the endpoint.
To your other question about how companies handle guest checkouts, this can be done a few ways but one way is to create your own token, this token would be an encrypted string that may contain a cart ID, time etc.
When a user clicks 'checkout' the token is generated and passed to the server via a get or post request. From there your server decodes the token and if everything is correct processes the order otherwise it kicks it back.
Again, you see a lot of token based stuff here going on and that because there is an X factor in all of this.. the user.. We know who the server is but the user can be from anywhere and the user isn't a server so we need some way to maintain state between servers, hence tokens, encryption, JWT etc

paypal rest sdk - cancel a payment gives only token

so i've seen some question about this subject but no good answer
after creating a paypal payment via paypal api, the client is being redirected to paypal for payment approval
the payment object also gets a "approved" and "cancelled" urls so that paypal could let my server know what course of action took place within the client's approval process
if the client has cancelled the payment, the http request being sent from paypal looks like this:
/customerCancelled?token=EC-32W183225U612050A
when "customerCancelled" is a get method in my server of course
what paypal claims should be done here is just to cancel the payment in my DB because they already cancel it on theirs
the problem is here - what the hack is this token? its not the paymentID (which is the primary key of the payments in my database)
how does it help me identifying the payment object that was canceled?
it takes a lot of time until paypal answers questions.. so if anyone here has got a clue that would be helpful
thanks
I know this is old, but i dont think the Paypal .net API has improved much since this bug, and neither has the docs.
I noticed that the token you require was on the "approved_url"
I stripped it out, and saved it, so if the cancel is returned, you can look up your order via that token.
I have discovered it. When you enter the cancel URL first you have to ask for access token (if you dont have it stored), then get the payment information (here you can see) and the response contains a cart value, the cart value is same that the token without EC-, I mean, if cart value is 1234567890 the token you have is EC-1234567890.
When you create the payment store in your database (or elsewhere) the payment id, cart value and the final token. Then on cancel you search the cart value in your database and you obtain the Payment ID.
Did I explain?

Spoofing a Paypal Hosted Page Silent Post

I am building out a registration system using PayPal Hosted Pages. From what I understand I can use the Silent POST feature to let my application know when a successful transaction has occurred on the hosted checkout page. I worry that it will be possible to spoof this POST request and manipulate my application into thinking a transaction was successful.
Example:
When a user checks out they are redirected to a URL like
https://payflowlink.paypal.com/?MODE=TEST&SECURETOKENID=XXX&SECURETOKEN=YYY
They can copy XXX and YYY and use an application like cURL to send a POST request to my application endpoint, thus tricking into thinking there was a successful transaction.
Is there a preferred method of securely handling silent POST requests to prevent this scenario? Is there a better method altogether of notifying my application of a successful transaction?
You can use a userid/and matching secure key as well as a date stamp, that way, only a random generated secure key, and a user id can be used, for a given time frame (usually couple minutes)...

How to implement 3d secure payment securely

I'm wondering what's the best way of accepting payments from credit cards that require 3-D Secure verification. Currently the checkout flow is like this:
Customer submits payment
Payment gateway returns an error stating that the card requires 3-D secure code processing. Returns the ACS URL in the response
I redirect user to the issuing bank's verification site and I pass a callback URL for the ACS to redirect after completion of verification
Customer enters verification code and ACS redirects to the callback URL with an authorization token indicating successful verification
To complete the process, I have to resubmit the original request with the authorization token to the payment gateway
My problem is in the final step. As I need to resubmit the original request (which contains the credit card information of the customer), I need to store it somewhere temporarily so I can retrieve it when the callback URL is called. Is there an alternative to this?
I'm thinking of trying an iframe solution: The original form is never closed and I display the verification process in an iframe. When the process completes, i.e. the callback url is called, I hide the iframe and update the original form with the needed values and resubmit. Has anyone tried this technique before?
As you might already noticed in article you linked, presenting bank's page in iframe is a preferred option. Although if you read in further, it presents other security features, specifically in regard to phishing protection. Because your client won't know to whom is he really sending his password.
But going back to your proposition, if you present it in iframe or popup window, you would be able to store the original form on your base page and then resubmit it with received authentication token. It's a very good idea because you would not need to do any PCI compliance stuff. So not only it's easier for you it is recommended :).
With Sage Pay (and I would assume other payment providers) you don't need to pass the full order information again in the last step, just the response code from the 3D Secure form and a unique transaction reference. Storing the card details is therefore not necessary.
For me the process is:
Card details etc. and unique transaction reference submitted to payment gateway.
Payment gateway responds with 3D secure details (ACSURL and reference codes).
Redirect user to 3D Secure form (passing ref codes and callback URL) where they enter their details.
Verification code passed back to callback URL.
Server must send the verification code and same transaction reference from step 1 to the payment gateway.
Payment gateway responds with success/failure information.
I've done some recent work with 3d secure. From my personal experience:
I pass the credit card information with a forward url to the banks
3d secure url.
The user is redirected to the 3d secure url and prompted to type in his password.
When he clicks continue, the user is passed to the forward url with the authorization token -- the credit card information gets passed along as well.

Does the Dwolla API Webhooks Notification send the wrong transaction id?

I think that the Dwolla API sends the wrong transaction ID in notifications. In a normal dwolla money transaction, two transaction IDs are created (this is weird to me, but that's how dwolla does it). Because these two are created at the same time, they are always (in my experience) consecutive numbers.
So e.g. if account X sends money to account Y, Y will see transaction id M, and X will see transaction id M+1.
But Dwolla's notification webhook will send Y details of the transaction with id M+1. While ID M+1 is still unique to this transaction, ID M+1 cannot be used by Y via the API - because M+1 is supposed to only be used by X.
Here is a specific example:
Via my webapp, I send money from my personal dwolla account to my organization's via the off-site gateway api.
My webapp is sent the transaction details in both callback and notification form. The transaction id generated by step 1 is 1431566. This is the transaction id sent to both callback and notification. My web app stores this Id for future use.
Via my webapp, I decide to refund my personal dwolla account from my organization's so:
My webapp tries to query dwolla about transaction 1431566, to get the SourceId, but this fails - dwolla reports "Transaction not found for account". My automatic refund cannot continue without an ugly kludge like subtracting one from the Id and trying again.
The manual workaround is to login to my organization's dwolla account via the web interface. Here I can look for the transaction based on datetime and I can see that the transaction ID is actually 1431565 (correctly reported in the web interface). If I go into my organization's database and replace 1431566 with 1431565, I can repeat step 4 and it works this time. After that I can initiate a send() and the refund goes through.
I reported the same problem here before dwolla moved support to stackoverflow: https://getsatisfaction.com/dwolla/topics/callback_and_webhook_notification_sent_wrong_transaction_id_off_by_one
I figure it will be fixed faster if other people have the same problem. Or maybe I'm missing something obvious and someone will point it out.
Thanks to Michael's help, we were able to get around this issue by using the receiver's OAuth token when getting the transaction details instead of the sender's OAuth token.
For example, say I send some money using the API and transactions 1202 for the money sender and 1201 for the money receiver get created. If you make the API call to get details for transaction 1202 but use the receiver's OAuth token, it will give you details for transaction 1201, including fee information.
I'm not sure if the situation is exactly the same since we are acting as the facilitator between two transactions, so no guarantees that this will work in your situation. But it's worth a try.
So, your application's key & secret can access the transaction ID posted to you by passing the transactionById() method your application's client_id and client_secret, as opposed to the oauth_token. Meaning, when you poll for the transaction, instead of querying this URL:
https://www.dwolla.com/oauth/rest/transactions/{transaction_id}?oauth_token=x
Query this url, instead:
https://www.dwolla.com/oauth/rest/transactions/{transaction_id}?client_id=x&client_secret=y
Makes sense?

Resources