I'm creating a web application where users earn points for using it (from time to time).
What is the best way to change the amount of points the user has in a safe way?
My first solution was to use a POST Request with the data in the body, but it would be easily circumvented since the user could open the console and send infinite copied requests and earn infinite points. And if I created a token, the user would copy that same token and reuse it until it is invalidated.
My second solution was to create a websocket that while the user maintains connection, he earns X points in X time but it would also be circumvented due to a false connection by the console
What to do in this situation?
Use a POST request, and validate that the request is authentic on the back-end (based upon the criteria in which it is deemed 'reasonable' to award the points).
For example, if a user could only earn 1 point every 30 minutes, store when the user was last awarded points in a database, and then ensure that 30 minutes had passed since that point in time (again, server side).
You could also ensure that the user isn't getting more points than the should by checking the value of the points that they are being awarded, in a similar manner. Want one point at a time? Check that their existing score equals their target score plus one.
Related
I am making a bot on Dialogflow with a Fulfillment. Considering the given strict 5-second window in DialogFlow, I am getting [empty response] as a response.
I want to overcome this issue, but my web service requires more than 9 seconds for the execution.
I am considering to redesigning the conversation flow in such a way that we will start streaming audio till the Response is processed.
Example:
User Question: xx xxx xxx xxxx xxxxx?
Response: a). We'll play fixed audio to keep the user engaged for few seconds till it finds a response text in the back end; b).
Receive answers from the web service and save them in the session to
display further.
How can I achieve this and how can I handle the Timeout issue?
You're on the right track, but there are a number of other things to consider.
First, however, keep in mind that anything that is trying to "avoid" the 5 second timeout already indicates some issues with the design. Waiting 10 seconds for a reply is a pretty long time with something as interactive as voice! Even 5 seconds, which is the timeout, is a long time. (And there is no way to change this timeout.)
So the first thing you may want to do is consider if there is a better/faster way to do what you want.
If not, the rough approach would be something like this:
Get the request from the user.
Track a unique identifier, either tied to the user or tied to the session. You'll be using this as a key into some kind of database or data store.
Start the API call as part of an asynchronous request or in another thread.
Reply immediately that you're working on it in a way that the user will send another request. (See below for this issue.) You'll want to make sure that the ID is maintained as part of this session - so you'll need to save it as part of the Session data.
At this point - you're basically doing two things in parallel.
When the API call completes, it needs to save the result in the datastore against the identifier. (It can't save it in the session itself - that response was already sent back to the Assistant.)
You're also waiting for a reply from the user. When it comes in:
Check to see if you have a response saved for this session yet.
If not, then go back to step 4. (You may want to track how many times you get here and give up at some point.)
If you do have the result, reply to the user with the information.
There is an issue with how you reply in step 4, since you want to do something that will guarantee you another request from the person expecting an answer. There are a few possible approaches:
The most straightforward way would be to send back a Media response to play a few seconds of "hold music". This has the advantage that, when the music stops, it will send an event to Dialogflow which you can capture as an Intent and then continue with step 5.
But there are some problems:
Not all versions of the Assistant support the Media response. You will need to check to confirm the feature is supported before you use it and, if not, use another approach (see below).
The media player that is presented on some Assistants allow the user to stop playback, or will not correctly send an event when the audio stops in some situations. So you may never get another request in this session.
Another approach involves some more advanced conversation design tricks, so may not always be suitable for your conversation. Your response can say that you're looking up the results but then ask the user a question - possibly one that is related to other information that you will need. With their reply, you can collect this information (if you need it) and then see if you have a result yet.
In some conversations - this works really well. For example, if you're looking up flights to somewhere, while you're looking that up you might ask them if they will need a hotel or rental car, which you might ask about anyway.
Other conversations, however, don't easily have such questions. In these cases, you may need to ask something that isn't relevant while you stall for time.
Question is related to CQRS - I have user that wants to order something from web and is presented with GUI showing his balance = 100$ and stock = 1 item. Let's say we have 2 services here AccountService and StockService with separate concerns. In order to generate GUI for client third service AggregatorService listens to domain events from AccountService and StockService, projects a view and creates GUI for clients.
When user decides to order this item, he clicks a button and Command for order is sent to AccountService. Here we load AccountAggregate in order to decrease balance for the price of the item that needs to be ordered. But before I can do this, I have to check if the item is still available (or somehow to reserve it). Only thing that comes up to my mind is:
Read current stock of the item from read model of StockService, but what can happen is that other services read model is updated just a second after I read it (e.g. somebody bought the item, so actual stock is =0. but read model still has =1).
Before decreasing a balance call some method on StockService to reserve the item for some time. If order is not successful (e.g. no enough funds on balance, I would have to un-reserve it somehow). This needs to be some sync-REST call and it is probably slower than some async solution (if any).
Are there any best practices for this kind of use-case?
You have 2 options, depending on whether you embrace eventual consistency or not.
Using immediate consistency I would have an OrderService that receives the order request and it makes async calls to AccountService.ReservePayment() and StockService.ReserveStock(). If either of those fail you call AccountService.UndoReservePayment() and StockService.UndoReserveStock(). If both succeed you call AccountService.CompleteReservePayment() and StockService.CompleteReserveStock(). Make sure each reservation should have a timestamp on it so a daemon process can occasionally run and Undo any reserves that are older than an hour or so.
This approach makes the user wait until both those services complete. If either the StockService or the AccountService are slow, the user experience is slow. I suggest a better way to do this is the eventual consistency approach which gives the user a very fast experience at the expense of receiving failure messages after the fact.
With eventual consistency you assume they have enough credit and you have enough inventory, and in response to their order request you immediately send back a success message. The user is happy and they go along to buy more stuff.
The OrderCreated event is then handled asynchronously to reserve stock and credit as described above. However, since there is no time pressure to reply to the waiting user you don’t have to scale up to handle as high a throughput. If the credit check and stock check take a minute or two, the user doesn’t care because he’s off doing other things.
The price you pay here is that the user may get a success message at the time of order submission, then a few minutes later get an email saying the sale didn’t go through after all because there’s no stock. This is what many large retailers do, including Amazon, Target, Walmart, etc. Eventual consistency can go a long way towards easing the load and cost of the back end.
I'm currently working on a app. This also includes some kind of group chats.
The users inside can make multiple votes, for example for kicking someone. The votes are all valid for 1 week. If all other users submit their opinion the vote gets deleted.So far so good.
I also want a logic, which deletes the vote automatically if it's expired.
So far I got the idea to store the expiration dates for the votes inside a database(MongoDB), sorted by their timestamp of expiration.
In NodeJs I'm always loading the vote with the smallest expiration date from the database.
Then I check how much time is left by subtracting the vote expiration date from the current Date
Date.now() - voteTmp;
Then I can set a timeout, which calls a function to delete the vote and automatically starts a new timeout for the next vote. Is it a problem to set a timeout with such a big number of seconds?
Do you have any better ideas?
Thank you:)
The node.js event loop is explained here:
when the event loop enters a given phase, it will perform any operations specific to that phase, then execute callbacks in that phase's queue until the queue has been exhausted or the maximum number of callbacks has executed.
On each iteration, the event loop checks for scheduled timers that satisfy the specified thresholds (delays) and executes their callbacks. Thus, the magnitude of delays for registered timers shouldn't matter.
However, in your scenario, there's a chance that you might accidentally register redundant or invalid timers (possibly after recovering from a crash). MongoDB supports (automatic) data expiration. You can instruct MongoDB to delete documents after a specified number of seconds has passed. That seems close enough to what you want to do.
https: xyz dot com/authenticate/cc.php
This is the page 3 of my registration....where my members enter their credit card. This is tied into my authorize.net account.
One thing i noticed recently is this page can be accessed on its own just by typing in the URL.. there is no required pre-url that leads up to it. This seems unsafe, but regardless if someone wanted to abuse it they could just go through the registration process and keep submitting incorrect CC numbers.. costing me money right?
I dont remember if we put an IP limit on it, or again if that is even 100% safeguard.
I am pretty sure we did something where if they enter mastercard with their number(temporarily stored) and it gets sent back as invalid it will match that and not allow them to keep entering the wrong 16 digit number.
Should i just leave the page accessible without specific pages allowing access and worrying about IP limits instead? Couldn't someone just keep switching their ip and submitting this page with incorrect CC's or fake ones at that?
What is the proper way to secure this page considering i/losing my merchant account could be the one at risk?
Thank you in advance
It is strange that you would allow direct acces to the 3rd step of the process, where is all the other data like the user name, addres, ...?
This are some ideas of what I would do, a completely secure system (which might not exists) would be much more complex than my simple steps.
note that you probably would like to first allow the users to register with some information where you can know who they are (verified email, verified phone number, etc) then and only then, you do the credit card thing, and if they continuosly input wrong or invalid numbers, you can do something else, like black-listing them, call them, insult them, etc..
note 2 I spent long time writting this, the more I read it and think about it, the worse it seems to be, but as it is already written I'll post it anyway.
Some notes before begin:
There is only one address, for example /authenticate/auth.php
The process has a "state" and depending on this, it will show/do different things.
For different states has other extra files which are included depending on the state.
After the process starts, a session is created and linked with the user IP, the process state and any other identifiable information about the user, for example 'User-Agent', this data is saved in the server.
Seems you would like to show a different state using different pages, so it will be like that. But actually I would do in a single page using ajax calls.
There is NO black-listing of suspicious IP addresses(too many normal or buggy or completely wrong requests), it could be added if desired, but the complexity increases. You might or might not want to do this, maybe a capcha would be enough, but..
There is NO capcha which might help in some cases, but the session handling I describe here might need to change.
There is NO email verification which you probably want to do.
Let's say that the process states are ask_name, ask_address, ask_cc, etc...
So, when there is any request to the auth page (/authenticate/auth.php), this is what we could do:
1 If 'Referer' doesn't come from one of the possible process starters (main page, etc,) or this page (/authenticate/auth.php), we redirect to the main page. end.
This first step avoids people writting the address directly or coming from untrusted pages.
2 If there is no session information for this request:
2.1 If there is a 'user_name' parameter AND 'Referer' is this page (/authenticate/auth.php)
2.1.1 If that user name is already registered, show(include, not redirect) 'ask_name.php' with the extra notice "User already registered". end.
2.1.2 Create a session for this user, link it with it's IP, User Agent, etc, other data.
2.1.3 Set the state to ask_address (the second) and show 'ask_address.php'. end.
2.2 Else (no parameter or 'Referer' was wrong)
2.2.1 Show 'ask_name.php'. end.
This second step either shows the first screen (ask_user) or the second (ask_name), it delays the creation of the session until we are sure the user wants to do something real.
It has a couple of problems:
Some user (or program) continuosly sends requests without session but with 'user_name', so forcing you to always check if the user is valid or not, and may slow things down. This could be avoided using several different techniquest, for example using a capcha or by black listing some IPs for some time.
It could be possible that one user start the process with a 'user_name' which doesn't exists, but he is slow and takes some time to finish the process, while this is happening, a second user begins and finish the process with the same 'user_name', so when the first user is going to finish, it will fail at the last step. This could be avoided with several different techniques which are left as an exercice.
3 If there is session information for this requests (this is the else to the previous step)
3.1 If referer is not this page OR the IP stored in the server is not the same as the current request OR some other data like User Agent is different OR the state is invalid (not in the list of states), remove the session id from the request (so the browser deletes it) and show 'ask_name.php' with the extra notice "Looks like your device changed!!!". end.
3.2 'include' the page for the state:
3.2.1 If the parameters are passed and are correct, set the state to the-next-state and show the page for it. If is the last state do something appropiate for the last state. end.
3.2.2 Show the same page for this state with an error message for the user to retry. end.
This last step tries to ensure that the request is not coming from a different computer and/or with stolen session keys.
Currenty, web sites gives generic messages to the users on invalid login attemps such as:
The username or password you entered is not valid
to protect e-mails from spammers. However, I read somewhere that this is not enough because sign up forms will warn user if the e-mail address is already taken. Therefore spammers can find valid e-mails by trying to fill registration forms not login forms.
The question: how can we prevent this? Is there a good way of handling this situation?
One quite nice way to prevent brute forcing is to add an increasing delay before checking.
A fairly good way is to add a 1 second delay before showing the error implying that the email is taken, then double that to 2 seconds, then 4 then 8 etc for the user. You could max this out at 16 seconds, or block the IP for 10 minutes after this for instance.
This way, real users get a 1, 2 or 4 second delay (not much), but bruteforcing becomes too laborious.