How would I secure a POST route for a web game? - node.js

I am currently learning full stack dev, and have made a simple application with React on the front end, and set up a very simple REST api on my express web server that handles certain routes.
For example api/users returns a list of users from my database and returns responses as JSON data. api/blogs can return a list of blogs in JSON with a get request, or post a blog with a post request.
Say in my application, a game, a user has value of gold which is stored in the DB with their username and other game info. In the game if they unlock something or 'win', their gold gets updated. I would assume I would have to make a PUT request to the api/users and edit their gold amount to the database. But I am dreadfully concern, couldnt they always just make a PUT request from the outside and increase their gold at will? What possible ways exist to authenticate this route only from the server or allowed? This part makes 0 sense to me
I have learned and been able to implement very basic user tokenization with JWT, and so only logged in users with a valid token can make a post of a blog for example. This is done by adding their token with bearer as a Authentication header in the request, which the server verifies.

What you describe sounds as if the Javascript code that runs on the frontend would decide that a user has earned 10 pieces of gold, say, and you then want to inform the backend about the decision in a secure manner. That will not work, for the reasons outlined in When doing a booking system, where would it be better to do? Back end or front end.
It highly depends on the nature of your game and its rules for earning gold how this could be implemented securely. For example, if you earn 10 pieces gold by solving a mathematical puzzle within 1 minute, it could work like this:
The backend comes up with a puzzle "What are the prime factors of 2758238235918?" and stores the expected answer together with the deadline in its database, e.g.
{"user": "oscar",
"puzzleID": "ab45ga4753",
"answer": [2, 3, 3, 11, 71, 7993, 24547],
"deadline": "2022-07-09T20:11:00+02:00"}
It sends the puzzle to the frontend with an HTML form that contains a hidden input field with the puzzleID and a visible input field answer.
The user submits the form with their answer in a POST request to the backend.
The backend looks up the answer from its database (based on the puzzleID in the POST request) and compares that to the answer from the POST request. It also checks whether the deadline has not yet passed.
If the answer was correct and in time, then the backend updates the gold in the user record.

Related

How do I prevent multiple paypal payments in nodeJs?

I am really new to node js and trying to integrate Paypal's Payment Gateway into my application.
Upon the success of the payment, the user is redirected to http://localhost:3000/success?paymentId=PAYID-M8MU148234F&token=EC-2111Y&PayerID=YX82JX6Q where our code executes the order and return a payment object (contains order details).
On this page, I want to display the order details to the user.
I want to store the payment object as a JSON.stringify into my Mongoose database for future reference. The issue is that if the user keeps on reloading this page, the code inside app.get('/success'..) will keep on adding the same columns to the mongoose database repeatedly. I am not sure how to prevent that.
Since the payment is actually executed only when this URL is visited by the user, multiple reloads by the user blocks me from Paypal API and gives me the following error:
response: {
name: 'MAX_NUMBER_OF_PAYMENT_ATTEMPTS_EXCEEDED',
message: 'You have exceeded the maximum number of 20 payment attempts.',
information_link: 'https://developer.paypal.com/docs/api/payments/#errors',..........
The only solution I can think of right now is that somehow my /success route executes the payment and stores the data onto the database and then redirects the user to maybe /someOtherPage/ page with the order details as headers. I am not sure how to make this redirect happen and also pass some context (the payment object) at the same time.
You are using a deprecated v1/payments API and/or PayPal-Node-SDK. You should change your integration to the current v2/checkout/orders and Checkout-NodeJS-SDK.
Make two routes on your server, one for 'Create Order' and one for 'Capture Order', documented here. These routes should return only JSON data (no HTML or text). The latter one should (on success) store the payment details in your database before it does the return (particularly purchase_units[0].payments.captures[0].id, the PayPal transaction ID)
Pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
The above mostly takes care of this issue and is the recommended solution, as it does not rely on redirects and gives an improved user experience that increases buyer confidence by keeping your site loaded in the background. But to more directly address the issue posed here: when doing an execute or capture API call, set the PayPal-Request-Id HTTP header to something that will persist across retries that are not expected to result in new actions/transactions -- for example simply set this header to the PAYID or OrderId being acted on. This will give idempotent behavior (see API idempotency)

api design - How to design public POST api to prevent spam request

I am developing a public website
One of the page is to let people submit opinions.
They need to enter email, phone, message ,etc, in order to submit the opinion form.
This means I need to make an api for people, so that after they press the submit button, the POST request will be sent.
But some people might abuse this function(e.g. create bot to send massive amount of POST request).
Since the frontend design is already finished and no recapcha is used in frontend, I was thinking if there are backend ways to do it.
Is there any ways/best practice to prevent this kind of things?
I am using node.js(aws lambda) for my api function
Yes, if there is still a way to implement captchas, use package "svg-captcha". If you only want to deal with the backend, refer to this header: req.headers['user-agent'];, so you can track down those who abuse the requests and limit their access for a while.

What is the difference between query and request

English is not my native language and i don't understand difference between query and request.
What is the difference between words and how to use them correctly on the web
Request means ask for something and it shall be given. You need that thing.
Query means ask whether or not something is true/ available or false/not available, you may not get that thing back but you'll get the status, state or info.
Request means ask to collect that object.
Query means ask to confirm the state of an object ex. Availability, true/false,
Can I have some food to eat? You are requesting for food.
Is that way good? This is a Query:
A request is like when I ask you to go to the supermarket. Here, I’m requesting you to leave your current place, go to the supermarket to bring one or many items and come back. Now, you can go to the supermarket but once you arrive you will ask yourself, what should I bring? In order to make your visit to the supermarket successful, I should give you a list of things that you need to bring or do at the supermarket, give you a description for the items and tell you in which aisle or department you can find them. This list now is representing your query.
So, if your client needs to fetch some data for example from a remote server, you will need to make a request. This request has a type, like ‘GET’ to fetch resources or data back, or ‘POST’ to do an operation like creating a new user account.
For the request to do its job, you have to specify what data or resources you need this request to fetch and where to find it. It’s like what items do you need to buy from the supermarket and from which aisle can you find them. For example, your request can have a query to return a specific user’s data based on his id. But you need to know to whom should you send the request with this query in order to get the user’s data back based on the passed id.
In order to make a request, you need to send it to your backend’s application that you can access using an IP or a domain mapped to it. Something like: “http://www.mywebsite.com”. But to fetch specific type of data, like the user’s data you need to tell your backend application what are you searching for. This is specified by something called the “path”. For example: “http://www.mywebsite.com/users”. The path here is the “/users” part. The query works when you submit to this domain with the path one or more query parameters, like the user’s id. So, you will make a GET request to “http://www.mywebsite.com/users/1234”, where “1234” here is representing the user’s id that you need to fetch its data. It’s like telling you to go to the supermarket named “mywebsite.com”, go to the “users” isle or department and grab the item with the id “1234”.
I hope that I managed to simplify the concepts a little bit for you.
Mohammed's answer above is great and very detailed. In summary:
First of all, query and request can both be nouns and verbs. E.g:
I requested a refund.
We received a request for a refund.
I queried the price.
We received a query about the price.
To request something is to ask for something, an object or a favour etc. A request is a polite demand. To query is to ask about something i.e. you are wanting information. A query is a question.
Also, QUERY is an inquiry(Query and inquiry are synonyms)
They are both requests but the difference is that the QUERY is a precise request. In informatics, if you need information about something you need to send a specific request with precise information.
"I queried information about user account Maxim Pavlov" = "I need to know about this website users. In particular, I need to know if there is any Maxim Pavlov registered on this site".
If you are Arabic, best translations in Arabic would be, request = طلب and query = إستعلام)
I thought about this question and I think the Ahmed's answer is misleading to say the least.
When web developers talk about request, they usually mean request done via HTTP. There are other protocols, but HTTP is certainly the most common. Request tend to be fourfold: get, post, put and delete. A request is almost always associated with an endpoint. A request is more than just ask for something. For instance, a put request is basically either add information or a file stored on a web server or update it. On the other hand, a query, in the language of a web developer, typically means some information he would like to extract from the database where a certain condition needs to be met.
I will give you an example. When building an API, you may have just two endpoints which are mapping to a post request and a get request. When you hit the endpoint associated with the get request, by design it will always return the "current time" which requires no query in a database. Meanwhile, when you hit the endpoint associated with the post request, by design it will always get the leap years between, say, 1900 and 2000 which are all stored in the database and requires a database query to fetch that information back to you.
The Abdullatif's answer is by and large correct though.

Caching response for API.ai Node.js webhook

I have a webhook designed in Node.js for API.ai that interacts with multiple API's to gather information and give response to user.
Since, I am interacting with multiple API's the response time taken is more than 5 secs which is causing the API.ai request to timeout.
To overcome this, I am trying to implement caching into the node.js webhook which saves the response from API's until a certain amount of time. This will remove timeout until the max-age header time is reached.
Edit: What is the best node module that I can use to cache the API responses for subsequest requests.
Note: I am using request node module for http requests but it doesnt seem to provide a way to cache the response.
All of the answers given are reasonable for tackling the cache problem on the request side. But since you specified API.AI and Actions, you might also be able to, or need to, store information while the conversation is in progress. You can do this using an API.AI context.
It may even be that if you limit it to just one remote call for each response from the user, you might be able to fit it in the timeframe.
For example, if you were having a conversation about movie times and ticket ordering, the conversation may go something like:
User: "I want to see a movie."
[You use an API to lookup the nearest theater, store the theater's location in a context and reply] "Your nearest theater is the Mall Megaplex. Are you interested in one there?"
User: "Sure"
[You now already have the theater, so you query for what it is playing with another API call and store it in a context] "There are seven different movies playing, including Star Wars and Jaws. Do those sound interesting?"
User: "No"
[You already have the data in the context, so you don't need another call.] "How about Rocky or..."
In this way you're making the same number of calls (generally), but storing the user's results in the session as you go as opposed to collecting all the information for the user, or all the possible results, and then narrowing them.
Finally decided to use the below module:
https://www.npmjs.com/package/memory-cache
This served my scenario better. Might try using Redis soon when i get some time.

How can I create an authenticated scraper for Amazon product detail in Node.js?

I'm creating a script that grabs all the shipped items from Amazon and notifies me.
Authentication is needed to see the products though.
I've already tried sending a post request through "request" which returns an error because of the cookies and extra parameters needed.
It would be easy using cheerio afterwards to get the data if the authentication works.
Does anyone have any idea on how we can authenticate successfully?
The link from the email is: https://www.amazon.com/ap/signin/185-3199906-8918341?_encoding=UTF8&accountStatusPolicy=P1&openid.assoc_handle=usflex&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fgp%2Fyour-account%2Forder-details%2F185-3199906-8918341%3Fie%3DUTF8%26eoid%3D1%253A1%253Arv%252FYwjiYmnOZY9MYltVnDyf2l6p5pMkMx9deoUeiiw%252FKpPrtZrWqs5l1GGQPVb%2520qaJqHXyCkPEpLZnmDZamKkVDWhtu3dKlW5Gx7Uvxtzs0xlPJ25vduijJrPpHt79P%2520RRZHopOtAyOP4s82VLoeeiDQgq%2520FCP540H%2520UYAV7goZQxB29WObWAVh8VveTwEeWenY3sTx8ZI9%252FBLM2BSqS3IUIURW8mzMnAB9t7wglUiAcoR%252FcUhSIx%25201eNV4MspVAp7fLkeANag72BxgmsjFfRhnsxfji1VhZXLawqFeK9SBnvbUfkNWUC%2520IXWh6VcuoStBG3x%2520ZUkzGHw1ORi4J%2520Hg%253D%253D%26orderID%3D105-6914722-5422613%26ref_%3DTE_simp_on_T1&pageId=webcs-yourorder&showRmrMe=1
You cannot guarantee any of the form input values of the sign in page. So you must also scrape the login form.
Here is the process:
In your server, make Request to the URL in your question
Using Cheerio parse the DOM and grab all of the form fields from "#ap_signin_form".
Add in your data (Username/Pass) then make a POST request to the form action "https://www.amazon.com/ap/signin" (This should also be scraped)
Hopefully that will get you past the login screen. You will need to ensure all future requests pass the cookies set from login.
Now this kind of thing is clearly against most TOS's so I would urge caution in doing this kind of thing often.

Resources