views:

219

answers:

7

Hello, I've made a voting on comments like the one this website has(something similar), and I'm slightly concerned about possible http request misuse. You'll know what I mean after I show you the questionable code:

$.ajax({
  type: 'POST',
  url: 'http://localhost/comments/vote_down/' + post_id
});

Now its still on localhost but it will get to the web eventually. What if someone just makes some kind of script which will run n times this url http://localhost/comments/vote_down/post_id .

Not even user authentication is very helpful, you just tweak your malicious script to authenticate and you can do it again. How can I make this request more secure, what can I do? thank you

EDIT

I see some answers , not the ones I've been looking for so far.

Maybe I'm expecting too much, is there a way I can directly refuse this request to anyone but someone redirected from localhost(or website.com), after x attempts to do so .

Maybe some kind of header authentication? I'm not very into that that is the main reason why I ask.

EDIT

Also what I've discovered accidentaly about a minute or so ago, I was browsing trough few similar questions and my firebug was on, I added one question to favorites .. saw console post response 200 OK then I tried it for like 10 times just to see when will I be rejected to do the same again.. eventually I got bored .. so if StackOverflow didn't solve that .. what am I trying to do :=)

+5  A: 

At the bare minimum, you can make sure that every user can only vote once.

  • If user is not logged in, don't alow voting.
  • If user is logged in, restrict voting to one vote per comment (whether they can change the vote from up to down or not is up to you)
  • If you want to let unregistered users vote, lock them out with cookies and ip address and useragent checking. (Far from bulletproof, but will keep some troublemakers at bay)

Additional options:

  • Implement a captcha

In response to your edit:

If you are talking about checking for a valid referring page, you are out of luck. That is incredibly easily spoofed. You can implement a token check where you generate a hash that is valid for X seconds and deny all requests with an invalid or expired hash. This will not prevent people from voting multiple times though.

In response to your second edit:

A status code of 200 only means that the http request was successful, what the application logic decided to do with the request is a completely different issue. You can deny the vote and return a 200, just as you can return a 403 (which would probably be more appropriate in this case though).

code_burgar
@Whover downvoted: posting a reason would be nice :)
code_burgar
But each time I did I got the success here it is "{"Success":true,"NewScore":2,"Message":null,"LastVoteTypeId":null}"
Gandalf StormCrow
That does not mean the score was changed, a successful upvote returns: {"Success":true,"NewScore":2,"Message":"","LastVoteTypeId":2}Downvote:{"Success":true,"NewScore":0,"Message":"","LastVoteTypeId":3}Nothing happens: {"Success":true,"NewScore":1,"Message":null,"LastVoteTypeId":null}
code_burgar
ou ..ok tnx for the explanation
Gandalf StormCrow
A: 

I think you need to track which (authenticated) users voted on which items, and permit each user to vote on each item only once.

Drew Wills
A: 

Make the user login and check to see if they have voted it up/down before which would then require a votes table to contain a linkage to the user, hopefully through ID.

Hope this helps,

David
+3  A: 

You are going to have to do more than store the vote tally for a post id. You are going to have to store a record for each individual vote cast.

Once your database schema is set up for that, you can start to associate additional information with each vote - an IP address, user id, etc.

Most places only allow authenticated users to vote, and only allow a user to vote once for any given post id. Stackoverflow goes beyond that and allows users to undo their votes and recast them.

If requiring a user to be authenticated before they can vote is not acceptable, then you can go by IP address and then throttle the number of votes to be able to be cast from that IP at some interval. For instance, once a vote is cast from XXX.XXX.XXX.XXX, it cannot vote again for another 15 minutes. This will not break the Internet for people behind a proxy, but will reduce the amount of gaming that can be done.

You could go even further and try to detect someone gaming the system and then blacklist them for some amount of time.

Bryan Batchelder
- Stackoverflow goes beyond that and allows users to undo their votes and recast them. I like this one .. and I'm trying to do it as well
Gandalf StormCrow
I can recommend against restricting by IP address as you'll block plenty of legitimate users. Large companies, office parks and skyscrapers often NAT to a single IP address, and in fact some countries' ISPs route all traffic through a proxy server that replaces the IP with the Proxy's IP. Agree on storing a vote against a user though - it seems the only foolproof way to solve this is by requiring an authenticated user.
realworldcoder
A: 

You can use CAPTCHA (I recommend reCAPTCHA, since it contributes to digitizing printed works at the same time) for eliminating at least the bot-based votes. For preventing multiple human votes, consider counting based on a semi-unique identifier, such as IP Address plus the browser's User Agent string or something. Or validate the vote based on the user's account (and obviously put a CAPTCHA on your user registration page).

darvids0n
+1  A: 

You must authenticate via a token.

Potentially, I could just print a <img src="http://localhost/comments/vote_down/1"&gt; and start casting votes from users who are accessing my site.

What you must do is a server-side validation, let's say you will validating against a MD5 hash ( md5(1) = c4ca4238a0b923820dcc509a6f75849b )

http://localhost/comments/vote_down/1?hash=c4ca4238a0b923820dcc509a6f75849b

Now on your server you must hash the post_id and check if the hash params matches, if it does, then allow to vote.

But then I could still just keep spamming votes from users without knowing via <img src="http://localhost/comments/vote_down/1?hash=c4ca4238a0b923820dcc509a6f75849b"&gt;

What you'll have to do is hashing both the post_id and user_id (from session), that way one hash from one user won't be the same to another.

User: 1
Post_id: 1
md5(11) = 6512bd43d9caa6e02c990b0a82652dca

User: 2
Post_id: 1
md5(12) = c20ad4d76fe97759aa27a0c99bff6710

Obviously, you should salt the hash function, but even with out it, your app will be pretty secure that way.

metrobalderas
Such a nice idea! :D
TiuTalk
I am not seeing what this gains you over just associating a user id with a vote record. It appears to be extra complication for no extra functionality.
Bryan Batchelder
This still allows a single user to make a valid request more than once. If you make the hashed value unique per pageload, and expire the hash once the vote is cast, you are set.
sfrench
A: 

I hope this goes some way to help answer your question. Check out this website: https://panopticlick.eff.org/. Basically what it does is tries to identify you based on your various system settings, fonts installed, browser capabilities, timezone etc. I've just sent it around my office and so far we're all unique.

Now this method isn't entirely secure, because you can fake all this information by simply changing the data that gets sent to the server on each request, but you would have to KNOW that your website uses this technique in order to level an attack (security through obscurity).

I think I'd be inclined to take a multi-tiered approach to the problem. Because none of the methods are entirely secure, all you can do is stack them up.

  • Don't allow people to vote unless they have cookies enabled
  • Implement CAPTCHA for users who are not logged in
  • Profile users based on the hashes of their system setup (hash of the fonts installed, browser capabilities, timezone, etc)
  • Have a login system so users can login to vote

Now, when someone votes, you store their user id (if they have logged in), their system hashes and their cookie against their vote. This will prevent logged in users from voting, logging out and then voting again anonymously - because their system hashes and cookie (if they haven't bothered to clear it) will already be tied to a vote.

Something else you can do is make a tripwire to detect if the voting on a particular post is getting hammered in any particular direction. If it is getting hammered (say, 20 votes per minute for 10 minutes, and a large percentage of those votes have been in the same direction), try to profile the upvotes by looking at IP address, system hashes, etc. Based on an arbitrary percentage of possible malicious hits, you could lock voting on that post for 15 minutes.

None of these methods are entirely secure and for the sake of being concise I've left out a few things that you can do to easily expand on this idea. But I think a multi-tiered approach is key. Sure, someday a really determined user who doesn't mind solving captchas all day might figure out a way to rig your system, but as long as you have really good logs, you'll be able to profile this attack and respond to it.

Hope this helps

Cheers Iain

Iain Fraser