Authenticating POST requests - javascript

I'm creating a tampermonkey userscript that sends a POST request from a website containing the user's high score. Something like this for example:
$.post('https://example.com/scores', {
id: 123, high_score: 999,
});
However, the issue is it's very easy for users to forge a fake score and send their own POST request with a fake high_score. Would there be a way to somehow authenticate these requests so I could differentiate between real requests from my userscript and forged fake ones from users? Perhaps some encryption/decryption?

you can add a hidden input into your page with a nonce (number only used once it can be generated based on the platform you are using (unique identifier)) value in it, when you send the post read the value and add it to you post body, on the server side you check if this nonce exists in the database then this post is authentic otherwise it is not.
On your back end you could save this nonce with the session if you have sessions, this is an example
<input type="hidden" value="your-nonce" id="your-id">
<script>
let nonce = $("#your-id").val();
$.post('https://example.com/scores', {
id: 123, high_score: 999,nonce
});
</script>

Related

How to make safe PUT DELETE requests?

I am making backend for my project and I have a question about safety.
As an example my task is handle different "/notes" requests.
/notes => get all notes of authorized user
/notes => create new note
/notes => delete note
So... Reciving data is safe. Noone can get these notes from another URL because of CORS.
If we will use GET params to create or delete notes
/notes?action=delete&note_id=7
bad people can send link to authorized user and he will lose his data by accident.
So next step is making POST requests.
Everything is much better, but there is still a little hole. If someone will add post form with hidden input params it can be dangerous.
So last thing that I'd add is sending extra param, that only authorized user knows.
User ID
Temporary hash
or something like that.
Is there any other solutions?
/notes?action=delete&note_id=7
You need a know id of owner note smt like that:
$note_id = (int)$_GET['note_id'];
$note = 'SELECT * FROM `notes` WHERE `id` = $note_id'; (fetch)
if($user['id'] == $note['user_id']) {
//delete code
} else {
exit('Bye bye');
}

nodeJS Paypal REST API to revise plan give broken but working link

I'm trying to integrate Paypal into my app in NodeJS. I'm using REST API since the official npm packet is deprecated.
Let's suppose I have a product with two plans, planA and planB, necessary for recurring payments like subscriptions. Suppose a customer subscribe to planA, which costs 10$. After a while, he wants to switch to planB, which costs 20$, to unlock premium content in the platform.
I found the API: POST/v1/billing/subscriptions/{id}/revise
with which one should be able to send the planID planB to switch to it. You can also send effective_time field to specify when the change is effective. After calling this API, Paypal reply with 6 links, and I use the first (approve) to redirect the customer to Paypal domain to confirm it's will to switch the plan. After the user login, confirm and click "Accept and subscribe" to the new plan, the page always give me the following error: Things don't appear to be working at the moment. Please try again later.
, despite the plan change goes fine (I can verify it through dashboard).
I'm wondering what can I do to avoid that error.
I want to clarify that in the settings, through the dashboard, under Account settings -> Website payments -> Website preferences, I temporarily have the option Block non-encrypted website payment to Off.
Thank you all in advance!
The setting "Block non-encrypted website payment" is not relevant to this issue, and will have no effect. It applies exclusively to legacy HTML-only payments, which you should not concern yourself with.
Edit: ah yes, a redirect integration requires an application_context with a return_url. For usage with the SDK, no redirect_url is used, hence why the field is not required by the API.
Previous answer follows:
The issue you describe seems to be a problem with the PayPal site, and possibly only occurs in sandbox mode or with certain browsers/cookies. You can test as desired and contact PayPal's support if needed.
It is also possible to do a revise with the JS SDK rather than a redirect. For a client-side-only integration (no API), this can be done using actions.subscription.revise. Search for that text within the SDK reference.
To combine the JS SDK with the API call you are using, have your button code fetch the revised subscription ID from your server. Here is a sample for a create, which you can adapt to be a revise as it's essentially the same thing (you'd just likely be using a /revise endpoint /path/on/your/server)
<script src="https://www.paypal.com/sdk/js?client-id=..........&vault=true&intent=subscription"></script>
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
style: {
label:'subscribe' //Optional text in button
},
createSubscription: function(data, actions) {
return fetch('/path/on/your/server/paypal/subscription/create/', {
method: 'post'
}).then(function(res) {
return res.json();
}).then(function(serverData) {
console.log(serverData);
return serverData.id;
});
},
onApprove: function(data, actions) {
/* Optional: At this point, notify your server of the activated subscription...
fetch('/path/on/your/server/paypal/subscription/activated/' + data.subscriptionID , {
method: 'post'
}).then(function(res) {
return res.json();
}).then(function(serverData) {
//
});
*/
//You could additionally subscribe to a webhook for the BILLING.SUBSCRIPTION.ACTIVATED event (just in case), as well as other future subscription events
//Ref: https://developer.paypal.com/docs/api-basics/notifications/webhooks/event-names/#subscriptions
// Show a message to the buyer, or redirect to a success page
alert('You successfully subscribed! ' + data.subscriptionID);
}
}).render('#paypal-button-container');
</script>

Paypal integration to Flask application

I am slightly misunderstand Paypal flow event after reading https://developer.paypal.com/docs/api/. I'd like to integrate express checkout and credit card payments to my site. I am using Flask and paypalrestsdk without any Flask extensions.
Here is excerpts from my app:
#app.route('/', methods=['GET'])
def index():
# Page with but form, price/quantity/name values
# are stored in hidden fields, "Buy now" acts as submit
return render_template('index.html')
#app.route('/payment/paypal', methods=['POST'])
def payment_paypal():
# Here I am creating dict with required params
payment_template = {
'intent': 'sale',
'payer': {'payment_method': 'paypal'},
'redirect_urls': {
'return_url': url_for('payment_paypal_execute'),
'cancel_url': url_for('payment_paypal_error')
},
......
}
payment = paypalrestsdk.Payment(payment)
if payment.create():
print('Payment "{}" created successfully'.format(payment.id))
for link in payment.links:
if link.method == "REDIRECT":
redirect_url = str(link.href)
print('Redirect for approval: {}'.format(redirect_url))
return redirect(redirect_urls)
#app.route('/payment/paypal/execute', methods=['GET'])
def payment_paypal_execute():
payer_id = request.args.get('payerId')
payment_id = request.args.get('paymentId')
token = request.args.get('token')
pending_payment = PayPalPayment.query.filter_by(token=token).filter_by(state='created').first_or_404()
try:
payment = paypalrestsdk.Payment.find(pending_payment.payment_id)
except paypalrestsdk.exceptions.ResourceNotFound as ex:
print('Paypal resource not found: {}'.format(ex))
abort(404)
if payment.execute({"payer_id": payer_id}):
pending_payment.state = payment.state
pending_payment.updated_at = datetime.strptime(payment.update_time, "%Y-%m-%dT%H:%M:%SZ")
db.session.commit()
return render_template('payment/success.html', payment_id=payment.id, state=payment.state)
return render_template('payment/error.html', payment_error=payment.error, step='Finallizing payment')
It is works fine, after clicking on button payment created succesfully (with state created) user redirected to approval page. There he click "Confirm"... And I never returned to my application, event when I specifying return_url! I.e. application could never be informed that buyer approved payment and it should be updated in my own database and new license should be sent to that person.
Problems:
I cannot find way to define some callback using pyhtonrestsdk. How to do it?
Even if I adding callback (I tried embed Express Checkout using pure Javascript button code) with data-callback my application was not called. I suspect because remote server could not call http://127.0.0.1/payment/paypal/success
User could close window with PayPal confirmation immediately after click "Confirm" so I could not trust browser redirection it it performed somehow later.
Finally, I suspect that I do not understand PayPal workflow clear, but I could not find more information about it event on developers portal.
As usual, devil hides in details. My main issue was following: paypal does not redirects me to my application, but I found that it redirects me (after confirmation) to URL which looks like https://sandbox.paypal.com/ with query string contains desired parameters. I.e. redirect_urls works as expected, just redirects me to wrong host.
After that I remembered that url_for generate relative links. So just added keyword _external=True I've been redirected to my application with all required arguments and payment successfully confirmed and executed.
I.e. correct redirect_urls block will looks like:
'redirect_urls': {
'return_url': url_for('payment_paypal_execute', _external=True),
'cancel_url': url_for('payment_paypal_error', _external=True)
}
Finally I've got following workflow:
Opened / (index) which has button Pay with PayPal It is image button inside form. Beside this button form contains hidden fields with amount, product name and quantity (actually if is not good idea because we cannot trust to user, so I storing only product_license_type_id which stored in DB and contains all required information about product).
Once clicked it POST form to '/payment/paypal' (paypal_create) where create object Payment with filling all fields. If call payment.create finished successfully it also creates record in my own database with payment_id and state (these fields related to paypal workflow, of course actually I am storing couple of other fields related to my app).
Once payment created on PayPal side, application look into response for list payment.links. We want one with rel == 'approval_url' and method == 'REDIRECT' and return flask.redirect(found_link)
On PayPal site buyer should click 'Approve', review shipping address and after that he will be immediately redirected to redirect_urls.return_url with following parameters in query string: PayerID, paymentId, token.
Once redirected back you should get this parameters from query string (keep in mind - it is case-sensitive!), find payment using PayPal API (payment = paypalrestsdk.Payment.find(payment_id)) and finalize it (payment.execute({"payer_id": payer_id}):).
When finalized payment changes status to approved.
....
PROFIT!
UPD: You do not need to turn on "AutoRedirect" in you selling account preferences and this approach suitable for integrating one account into multiple sites.

How should i send sensible data using JSON?

im making a webservice in JSON to get the user data. for example i pass the user id and get the address of that user or i pass the user id and i get his favorites.
for example:
<script>
$.post('http://www.example.com/webservices/get-address.php', {
userid: "13"
}, function(data) {
$.each(data, function(index) {
alert(data[index].address);
});
}, "json");
</script>
but anyone could change the userid: 13 for userid:14 and get the address of other user.
(i cant use PHP on Mobile APPs so i cant use $_SESSION['id'], i will use localstorage to store the user id)
maybe i should mask the user id with a md5() so they cant guess the "user id" of other users?
which is the correct way to do it?
You need a session cookie. They are negotiated when you visit and log in and are trackable. Also, you should use ssl to avoid sniffing of data.
You need to track your session id at the server end somewhere and link it to the user, so if they ask for a user they aren't allowed to see, you return a 4xx code informing them that they aren't allowed to access that resource.
You could use a tripcode as some anonymous boards do, but then you're more limited to providing the facility to see groups of people etc.

Redirect from JavaScript

I'm working on an internal web app and we are using secure query string keys generated server side for some simple security to prevent users from accessing pages they haven't been given access to. The page I am currently working on grabs data via AJAX calls and renders it in a table on the page. Each row has an edit button that will take the user to an edit page with more information, with the id of the row kept in the query string. Since every row id is unique, the key for every edit page will be unique to that row-user combination.
My problem is that I need to be able to get these secure query string keys from the server in some way that allows the JavaScript to redirect the user. I can't move the key generator client side because that opens up the possibility of users generating their own keys for pages they don't have permission to visit. And similarly I can't expose the generator in a web service.
Basically what this boils down to is I am stumped in finding a way to send data from the client to the server in order to generate a secure key and then redirect the user to the new page.
Not exactly sure if I am being 100% clear but I'll edit this as questions come in.
Your question is a little unclear, but PageMethods might work for this:
[WebMethod]
public static string GetSecureID()
{
return "Secure";
}
clientRedirectSecure = function() {
PageMethods.GetSecureID(onSuccess, onFailure);
}
onSuccess = function(result) {
window.location.href = "somepage.aspx?id=" + result;
}
onFailure = function(error) {
alert(error);
}
Here's an article that discusses PageMethods:
http://blogs.microsoft.co.il/blogs/gilf/archive/2008/10/04/asp-net-ajax-pagemethods.aspx

Categories