Rails 2, session & token - ruby-on-rails

i have a question-answer survey..
Only one user can answer on survey! User cant click on previous button (in browser) and once again pass the survey. How i can possible do this? I need sessions and unique token? Please help me, i;m stuck with this...

If you have user-login, then you only need to validate whether they have already voted or not. This is really required to be 100% sure of no dup votes.
If not, you can't 100% guarantee dup votes, but you could make it difficult:
store in the session[:voted] = true
on receiving a vote submission don't accept if session[:voted] == true
Obviously the user can clear cookies which will clear your session.
You could enhance this by logging ip's but then consider proxy-servers (all users from behind the proxy will appear as coming from the same IP -- the proxy).

I you must enforce this then I imagine you'd require users to login and then you can store which surveys / survey sections they have already answered in your database.
Otherwise it's generally enough to prevent people from filling in surveys multiple times by storing their ip address in your system and also setting cookies on their browser based on which sections they have already completed. They can get around this by clearing their cookies but at least if you store their ip address they'd need to change ip to redo the survey.
It's hard to say without knowing the context of the survey. Is it on an existing app where users already have accounts? Is it standalone etc.

Thnanks guys for respons.
I thought about this (user-login), but i want to without it.. so i give link address, user get it, click on this address.. like www.blabalbla.com/test/survey/32643928569832569 (unique token).. and user can pass survey.. then when he finished he cant pass this survey again on this link.

Related

How do I hide my API calls / routes from users of my Rails app?

I'm writing an app that make some calls to my API that have restrictions. If users were to figure out what these url routes were and the proper parameters and how to specify them, then they could exploit it right?
For example if casting a vote on something and I only want users to be able to cast one vote, a user knowing the route:
get '/castvote/' => 'votemanager#castvote'
could be problematic, could it not? Is it easy to figure out these API routes?
Does anyone know any ways to remove the possibility of this happening?
There is no way to hide AJAX calls - if nothing else, one just needs to open Developer Tools - Network panel, and simply see what was sent. Everything on clientside is an open book, if you just know how to read it.
Instead, do validation on serverside: in your example, record the votes and users that cast them; if a vote was already recorded by that user, don't let them do it again.
Your API should have authorization built into it. Only authorized users having specific access scopes should be allowed to consume your API. Checkout Doorkeeper and cancancan gems provided by the rails community.
As others have said, adding access_tokens/username/password authorisation is a good place to start. Also, if your application should only allow one vote per user, then this should be validated by your application logic on the server
This is a broader problem. There's no way to stop users from figuring out how voting works and trying to game it but there are different techniques used to make it harder. I list some solutions from least to most effective here:
Using a nonce or proof of work, in case of Rails this is implemented through authenticity token for non-GET requests. This will require user to at least load the page before voting, therefore limiting scripted replay attacks
Recording IP address or other identifiable information (i.e. browser fingerprinting). This will limit number of votes from a single device
Requiring signup. This is what other answers suggest
Requiring third-party login (i.e. Facebook, Twitter)
Require payment to cast a vote (like in tv talent shows)
None of those methods is perfect and you can quickly come up with ways to trick any of them.
The real question is what your threat model and how hard you want it to make for users to cast fake votes. From my practical experience requiring third-party login will ensure most votes are valid in typical use cases.

Managing write access through cookies

I'd like for people to "vote" on things without having to be logged in. The way I'm thinking of doing this is via a cookie.
What would be a recommended way for tracking these cookies per a post?
E.g, a user views a post, and then "votes it." Now that post vote is stored in a cookie and when that user visits that page it'll say they voted for it.
Should I create a cookie per post, or a cookie that is a hash of all the posts they voted on?
Tips/examples of code would be appreciated. Thank you.
You can access cookies via cookies[:cookie_name]. More details here: http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html
I think you are going in the right direction, cookies are made for this type needs only for storing insensitive information like the search history. Just remember not to give the cookie any expire time and it will remain stored in the users browser, and most of the normal users won't be clearing cookies so it will not be a problem for you.
you can use it like this cookies[:voted] = true put this when you register a vote, and every time before voting check this
if cookies[:voted]
return # or show that you have already voted
if you also want to save the vote that they caste last time you can just save that in the cookie for retrieving the next time.

Rails prevent double vote via cookies?

Relatively new rails programmer here, so bear with me.
I have an app where registered users can create polls but anyone can answer the polls.
I am using Devise for my authentication. I want non-authenticated users to be able to answer the polls but I want to prevent double-voting.
I assume this should be done with persistent (not session) cookies, but I'm not sure. So when the user enters the site, I create a user in devise and I store some random value in both the User model and in the cookie, and I check that the user has not answered the question previously when he/she attempts to load my "answer" page?
Can someone give me some advice on whether this is the right approach and/or point me towards a resource to help me get started?
I have found relatively little information out there on how to manage persistent cookies in Rails.
You can't reliably prevent people from voting multiple times without logging in. It's not possible. I guess people could also create multiple user accounts to vote so there is no fool proof way.
Cookies are often cleared automatically by certain popular cleaners and unless you are only going to allow people to vote on a product they have purchased I think you are kind fighting a lost battle.
Stack Overflow limits voting capability by making sure a certain level has been achieved before being allowed to vote but I guess that's not really applicable to your scenario.
This is not so much about sessions and cookies and more about setting up your database to record a vote including the voter id.
In the view that allows users to vote I would suggest that you switch between a voted icon and a vote now link depending on whether or not the currently logged in user has voted.
To determine if the user has voted then include the user id of the currently logged in user in a question_vote xref table.
For the belt and braces approach to prevent abuse of the html in the browser add the check to the validations of the question_vote record.
I would do this by adding a can_vote? method to the user model that accepts a question id as a parameter then you can use the question_id plus the user id to find a matching record in the question_vote table if a reordx is found return false otherwise return true

voting - stopping abuse from client side - ASP.NET MVC

so I have designed this voting thing which does not let somebody vote for the same article twice in 24 hours. However, suppose a person votes and after seeing the person was able to cast vote or that he is falling in that 24 hour window, I disable the vote-casting button (and this is all Ajax btw).
But what to do when a person closes his/her browser and comes back up or even refreshes the page? Obviously, he would not be able to cast vote, because of my algorithm, but the person would still end up succeeding in making call to the server. So if he really wanted, he would keep refreshing the page and clicking on the vote and put unnecessary load on the server. How to avoid that by doing some sort of client-side thing or something?
I am using ASP.NET MVC, so session variables are out of question.
Am I being over-concerned by this?
If voting happens only from logged in (known) members then you shouldn't have any problem.
If, on the other hand, everyone can vote then you need to store all user vote events:
timestamp
poll
poll_vote
ip
user agent
user uniqueness cookie
So you'll need a random hash sent out as cookie. This will ensure that you don't accept another vote for the same poll from the same person.
If the user deletes his cookies you fallback to plan B, where you don't allow more than (say) 10 votes from the same IP and user agent combination for 24 hours.
The system is not perfect since users can change IPs and (more easily) user agents. You'd need advanced pattern detection algorithms to detect suspicious votes. The good thing about storing all user vote events is that you can process these later on using a scheduler, or outsource the votes to someone else who can process them for you.
Good luck
Refreshing is not a problem
If you're doing all this voting using Ajax, refreshing a page won't do anything except load the page using GET.
If you're not using Ajax you should make sure you call RedirectToAction/RedirectToRoute action result, that would as well help you avoid refresh problems.
How do you recognise users
If you use some sort of user authentication this re-voting is not a problem. But if your users are plain anonymous, you should store IP address with your votes. This is how things are usually done. This makes it possible to avoid session variables as well. But you have to be aware of this technique because it's not 100% perfect.
Cookies?
You could of course also use absolute expiration cookies. They'd expire in an day. Advanced users would of course be able to avoid your voting restrictions, but they would be able to avoid other ways as well. Sessions BTW are also based on cookies anyway.
Combination
But when you'd like to make you system as great as possible, you'll probably use a combination of the above.
The best way would be to track who voted for what and when on the server (probably storing it in a database). In order to do this you must use an authentication system on your site (probably forms authentication) to identify users. So every time someone tries to vote you check first in your data storage if he already voted and when and decide whether to validate the vote or not. This is the most reliable way.
If your site is anonymous (no authentication required to vote) then you could store a persistent cookie on the client computer that will last for 24 hours and indicate that a vote has already been cast from this computer. Remember though that cookies might be disabled, removed and are not a reliable way to identify a given user.
I am using ASP.NET MVC, so session
variables are out of question.
Any reason for that? Sessions are perfectly fine in ASP.NET MVC applications. It is in your case that they won't work because if the user closes the browser he will lose the session.
Obviously, he would not be able to
cast vote, because of my algorithm,
but the person would still end up
succeeding in making call to the
server. So if he really wanted, he
would keep refreshing the page and
clicking on the vote and put
unnecessary load on the server
Automated bots could also put unnecessary load to your server which is much more important than a single user clicking on F5.
If you just want to ensure the user can only vote once on an article then you just need to store a Set (i.e. HashSet) of all article id's that they've already voted on, then just check before allowing the vote.
If you still wanted a 24hr limit then you need to store a Dictionary<articleId,DateTime> then you can check if he has already voted for that article and if he has when it was.

Restricting multiple votes from the same person in a picture rating web application

I'm trying to write a web application in ASP.NET MVC that allows each user to vote for multiple pictures but does not allow them to vote multiple times for the same picture. Users are not authenticated. What should I save in the database or in cookies?
Store the votes in a database table with columns PictureId, UserId, Score, and add a composite unique constraint to the columns PictureId and UserId - this will ensure that there is only a single vote per user and picture.
With anonymous users, you have two options, neither of which are very good:
1) Track the user with a user id stored in a cookie. As long as the cookie persists. the user can't vote twice. However, they can delete or otherwise modify the cookie. They might have cookies turned off. They could have two different browsers open at the same time. Scripts for "cheating" (curl http://site/vote?score=5&pic_id=1) won't store a cookie anyways. Basically, you'll end up with people voting more than they should.
1.5 *
2) Track the user by IP address. This is essentially the opposite. Users can't vote twice, regardless of deleting cookies, switching browsers, etc. However, several people from the same household (using a DSL router) can only vote once combined. Many companies will similarly hide many users behind a single IP address. I think some ISPs do, too (AOL?). You'll end up with far fewer "votes" than legitimately should have been recorded.
So the question is do you want over or under votes? If you think cheating is likely, I'd go for #2. But if cheating is likely, that means there's an incentive. And if people realize their votes aren't counted (which they may not realize), they'll be unhappy.
After that, whether you store each vote as a row, or combine the votes into a single row (update pictures set num_votes = num_votes + 1, total_score = total_score + [submitted score]) is up to you.
1.5 The third option would be to record their vote and an email address, send them the email with a confirmation link and ask them to click it to record their vote. People can still cheat with fake email addresses, but it's not as likely as deleting a cookie.
Database records for unique, authenticated users, as Daniel Brückner suggests, has to be the way forward. Cookies are unreliable as, for example, they can be deleted or a user may use a different browser.
If your users are authenticated, then you can save UserIDs with Image votes.
If your users are anonymous, then systems tend to store their IP address with Image votes. It's not perfect, it's not 100% proof, but it works in majority of situations.

Resources