How can I prevent a form from being submitted more than once within 5 minutes?
Asked Answered
R

4

8

I recently found a huge security problem with my PM system that allows users to send a message as much as they want with a for loop in the address bar. Someone put this into the address bar:

javascript:for(x=0;x<10000;x++){ $('#compose form').submit(); }

And the message was sent 1000 times to me and my inbox was full of the same message and my database was so full that phpMyAdmin was being very laggy.

My question is, how can I prevent this? This is a major issue.

Also, the form is submitted with AJAX.

Edit:

I use PHP, so how can I prevent this? Like how could I make it to where a message can only be sent every 5 minutes or so and if they submit more than one within 5 minutes it will display an error (or not show any user feedback at all and just stop it from being submitted)?

Ratter answered 2/12, 2011 at 3:31 Comment(9)
You can't solve this with client-side code. It must be done on the server.Defloration
You can't control what happens in the browser; if you want to prevent this you'll need to do it on the server-side. Consider replacing this with a question focused on that.Silverstein
Deleted my answer...y'all are right ALL validation should be done client side AND server side...Stocks
You'll want to retag your question with the relevant server technology you use so you can find an appropriate server side solution.Trixie
@Trixie Okay I'll edit my question and retag it with my server side technology. (PHP)Ratter
Why are there 2 down votes? To the people that down voted: What is wrong with my question that made you want to down vote?Ratter
@Nathan, If I had to guess I'd say they down voted your question as originally asked and haven't come back for another look. Unfortunately StackOverflow doesn't give you any sort of notification if a question/post you downvoted later got edited.Romaic
@Romaic Yeah, that would be nice if it gave them a little notification because sometimes questions can improve.Ratter
@Ratter - I've learned not to let it get to me - upvotes, accepted answers, etc count a lot more than down votes anyways - and your question has had 72 views already - with some good suggestions - so, eh... just ignore em'.Romaic
K
3

There is one obvious way to fix it and the problem lies not on the client side - it lies on the server side.

Your server script should not allow sending messages too often - eg. often than, say, once each 10 minutes. To do it you can use session mechanism on the server side and save the information when the user sent the email. If user has not sent an email, you should also save that information in session - to distinguish people with session enabled from people with session disabled (and you should block the latter from sending emails at all).

The way session should be implemented (the specific code) depends on the language you use for server side scripting (PHP, Python, JSP etc.).

Kana answered 2/12, 2011 at 3:42 Comment(7)
A limit of one every ten minutes seems overly restrictive. Maybe the server processing could restrict duplicate messages to one every five minutes, while limiting unique messages to one every minute - or something like that.Pliable
@nnnnnn: It really depends on what is the site we are talking about. If this is personal site with couple tens hits per day and one contact form, then I believe 10 minutes is not too restrictive. It really depends on whether single user would need to send multiple emails during a couple of minutes. And there is another question: what frequency of receiving emails is acceptable to OP (if this is eg. 100 emails each hour, because they are directed between employees, then the limit should not be so restrictive as I proposed). Also think that it is not difficult to send mass unique emails.Kana
It would be better to invert the limit to say no more than x messages every hour rather than limiting based on some minimum time between individual messages. That would solve the problem without inconveniencing "normal" legit users. The OP mentioned his "PM system", so I assumed he was talking about some kind of forum/discussion type site where a normal user might reasonably expect to send a dozen or more short messages within ten minutes, but could not reasonably expect to keep doing so for hours on end.Pliable
@nnnnnn: Good point about PM system, I missed that. Anyway, I proposed once each 10 minutes in original answer, so it should be considered as time periods instead of difference between messages being sent (actually because it would be easier to clear such data with cronjobs). But I think it will not " solve the problem without inconveniencing "normal" legit users" - they have to take it as "normal" users should not spam others. They should understand (see SO mechanisms). As I said before length of periods (or breaks between emails) should be adjusted to OP's needs, it is hard to guess.Kana
I think that 1 or 2 messages per 3-5 minutes (per user, of course) would be fine. As long as they can't send a bunch of emails at once, then it's good. I wonder how Stack Overflow does their rate limiting for the comment votes.Ratter
Also, you mention "Your server script should not allow sending messages too often", but I don't know what to add to my server script to make sure each user will be limited to 1 or 2 messages per 3-5 minutes. I have a MySQL table field from_user so I can always see who it is from. (that's the way PM systems work) And I also record the IP that it is sent from.Ratter
If so, then you have two steps, that should be both executed for user (and both for IP, if you enable anonymous submissions) when determining if you should block sending the message: 1. find last message sent by specific user / from specific IP, 2. compare time of this last message to the current time (depending on how you want it to work: measure the time that has passed or check if it is in the same time period). The comparison will tell you if you should block it or not. It is not really that hard. Did it help?Kana
I
2

If someone has the knowledge to do this to you, you likely cannot do anything on the client side so the only option I'd say is that you log or keep a count etc of the number of requests (perhaps to a particular resource) and deny the request (or send a "busy" http code etc) for the particular user.

I think the simplest way would be to count requests from a specific IP address (this obviously has drawbacks such as multiple users behind a proxy or NAT etc).

The actual solution will depend on your server side language and web server but you could perhaps frame up a rule and see how it works. Something like 5 requests per minute (or whatever is appropriate for your usage) per IP address.

Infrequency answered 2/12, 2011 at 3:38 Comment(0)
T
2

As others have said, you have to implement protection on the server. No amount of client-side coding will provide protection.

The common way of protecting a server against this type of abuse is called rate limiting. You decide how often you want a given client to be able to submit a message and you code the server to ignore any messages that fall outside that limit.

For example, you could decide that you will allow no more than one message a minute and no more than two messages every 10 minutes and no more than four messages an hour. You pick whatever you think seems reasonable and you code to that algorithm.

In your server, you'd have to be able to identify which user the message was coming from (most likely via an authentication cookie) and in your database, you'd have to be able to find out when the last message was sent by that user. You may even be able to cache that information in RAM in your server (depending upon how your server works) to avoid a database lookup on every request since you only have to keep recent info and you only need to performance optimize on the repeat offenders (the ones that are trying to abuse your server and thus just recently sent a request).

Tendance answered 2/12, 2011 at 3:42 Comment(0)
R
1

I agree with what everyone is posting about rate-limiting.

However, this can be very complicated to implement on the server side. Especially when you start scaling out. And, honestly, if 1000 messages hurt you that bad - my suggestion may apply to you even more so.

Instead of implementing this yourself, you may want to look into a third party service to do it for you, such as this super cool web services proxy Apigee

One of their features is, specifically, API rate throttling. (see link)

enter image description here

Romaic answered 2/12, 2011 at 3:47 Comment(5)
Apigee looks cool. Does it cost money or is there a free plan? (I really don't want to have to pay for spam prevention/rate limiting)Ratter
Unfortunately it's fairly pricey.Romaic
Oh.. I take that back... maybe there is a free version? apigee.com/about/pricingRomaic
Wow, 50,000 API requests per hour is a lot! (especially for a free plan)Ratter
Give it a shot... Relatively easy to setup... make a few small DNS changes and you're all set. Compare that to trying to write your own software to track and limit API calls! No thanks!Romaic

© 2022 - 2024 — McMap. All rights reserved.