12

The new checkout of paypal make me feel insecure, can't a user trigger a fake payment on the cilent side?

The code provided look like this

paypal.Button.render({  
    env: 'sandbox',
    client: {
        sandbox: 'AapGZeCaaDK_q_KPeG19DHnD_kd18vr6BxNe4P6uuhfTKPjIedtNEI9plyDgmzfyI-xGhbxjpv0k-Ha9',
        production: 'xxxxxxxxx' // u expose the key to client side? is this ok?
    },
    payment: function() {
        var env    = this.props.env;
        var client = this.props.client;

        return paypal.rest.payment.create(env, client, {
            transactions: [{
                amount: { total: ($scope.number_of_uses * 9) + '.00' , currency: 'USD' },
                item_list: {
                    items: [{
                        "name": "example",
                        "quantity": $scope.number_of_uses,
                        "price": "9.00",
                        "currency": "USD"
                    }]
                }
            }],
            redirect_urls: {
                "return_url": $location.absUrl(),
                "cancel_url": $location.absUrl()
            }
        });
    },

    onAuthorize: function(data, actions) {
        return actions.payment.execute().then(function() {
            actions.payment.get().then(function(data){
                // here I will save data detail to db to record sales
                // $http something something 
            });
        });
    }

}, '#paypal-button');

In stripe, I have to pass a token to the back, then verify that token in my server side, if everything ok proceed to record the sales. But in paypal it seems like this is the only thing I need to implement to have express checkout. Is this even secure?

Panos Kalatzantonakis
  • 12,525
  • 8
  • 64
  • 85
Jessie Emerson
  • 743
  • 4
  • 12
  • 25
  • After the user hit the button they will be redirected to PayPal and required to provide either credit card details or login into their PayPal account. The *key* is only telling PayPal who the customer is paying to and the item_list tells PayPal what they're paying for. I don't see any insecurity here. All the secure stuff is happening on PayPal side. – Molda Dec 14 '16 at 15:11
  • @Molda meaning the user cannot trigger post request to my db? did you see the comment I put where my concern is? – Jessie Emerson Dec 14 '16 at 15:40
  • 3
    sorry missed that. This is basic integration method and it does not expect you to do this. It assumes you get the transaction data through different channel (just by login in to your account) What you could do is to send transaction ID to your server and pull the data from PayPal through rest API. You can also use advanced integration which creates payment through your server and than redirect the user to PayPal to confirm the payment. This ensure that the order data are on your server prior to creating a payment on PayPal. – Molda Dec 14 '16 at 16:06
  • 1
    means I cannot save my sales record using above code? I have to send the id then pull it through paypal API at the back? The reason is it's not safe to do like above method right? – Jessie Emerson Dec 14 '16 at 17:02
  • 2
    Yes, that's right. I believe that this basic integration is useful for static websites without any back-end. – Molda Dec 14 '16 at 18:27
  • 5
    Couldnt someone just change the `"price": "9.00"` line to set a lower price before checking out? – MoralCode Mar 24 '19 at 17:33

1 Answers1

7

You are correct that this isn't secure to update your database. This is a secure method of payment, however, you cannot verify with the client that the payment was successful and then update your database with the onAuthorize method.

To verify the payment was successful for your database you must use the Server Side REST API. Sadly, the PayPal docs for this are very lacking, however there are SDKs which are much more documented and easier to implement. (Shortcut to Node SDK).

I would recommend that you use these to implement an update to your database. PayPal returns an parameter that tells you payment was successful.

D. Clayton
  • 277
  • 2
  • 10