False Positives with Securtiy Token in a Form

I have a site with forms and as part of my anti hacking/bot measures I use a security token within the forms (among other things), which I believe is fairly common practice. The processing script also sends a report to me by email whenever something unusual occurs in a form submission to alert me to any attempted hack or bot activity. The report includes an IP lookup on the offending visitor.
Yesterday I got a report in from a problem form submission, the issue was with the security token. What struck me as odd about it was the IP lookup, it was someone local, like within two miles of me.
I have seen plenty of hack attempts on sites and they come from all over the world. This site is primarily of local interest, so the majority of visitors are local.
I got the day’s access log from the server and searched the IP there to track their activity and it first appeared to be a hack.
I see them browsing various different pages, at some point looking at forms, then going to other pages. There is a GET request on one form, then a 15 minute pause. Their next request is a POST on a different form to their previous GET request, but a form that had viewed earlier. That was the only post and coincides with the hack report.
So at first I find this very suspicious, a POST coming from a form another than the last one viewed?
But then the thought occurs to me: What if they viewed the form (that was submitted) then opened another browser tab and continued to navigate the site in that new tab and end up on another form, which creates new tokens and overwrites the sessions for the earlier form? Then they switch tabs to the earlier form and submit it.
Well I thought I would try it for myself, and yes, doing that creates exactly the same reaction and report that user got.

So my question is: has anyone come across this issue before? And do you have a method for dealing with this?
I have already been throwing some ideas around in my head, but not decided on anything solid just yet, and before reinventing the wheel I would see if the clever people here already have something.

I guess one of the points is how strictly you react to this kind of form “error”. If you are confident the offender is malicious you may go nuclear on them. But if there is a possibility of a false positive affecting an innocent, legitimate user, some measures could create a very bad UX.
In this case it blocked them from the form for the duration of their session, which was probably annoying for them, but at least I did not permanently blacklist their IP or something or print a message saying they are a scumbag. :laughing:
I thought as a quick fix to be friendlier, I could just display some generic error message like “Sorry, something went wrong with your form submission, please try again”.
But really there should be a smarter way to ensure this cannot happen and there are no false positives. Maybe by identifying each instance of a form and associating with its own token.
Any thoughts?

1 Like

Well, from what I know, when you create a token in a form and the user refreshes multiple times, but attempt to use an older token, it would cause a problem. What I think might be happening is the user copies the actual form, then go to a different page, go to the inspect tool and add the form in even though the page doesn’t have a submit form. And then they attempt to see if there’s a post request on those pages. IMO, I would of just blocked the IP and tell them that if they want to view my site again, they will have to email me with an explanation of what happened. I would say that if the person isn’t guilty, they would just contact you. If someone is guilty, they will most likely attempt to use a different IP. That’s just what I think. But fegall thought different.

Do you mind exposing an email address?

I think an error message something like this would be fair.

There was an error submitting the form.
Please send an email to me@example.com including the following information:
Your operating system
The browser used
The steps leading up to this error


I initially thought it was something like that.

IP - - [26/Apr/2017:07:26:51 -0700] "GET /form-A HTTP/1.1" 200 3471 "http://www.example.com/form-B" UserAgent

^ They went from form B to form A.

Then 15 mins later:-

IP - - [26/Apr/2017:07:41:15 -0700] "POST /form-B HTTP/1.1" 302 23 "http://www.example.com/form-B" UserAgent

^Post from form B.
Which I thought was iffy, like maybe they copied the html from form B, edited it for whatever means, then submitted from their version of it. Exactly the thing the token should prevent (and did, if that’s what happened).

But if the IP had been some random far flung place (or the usual places these things come from), I would not hesitate to believe that’s what happened and ban the IP.
Being local, that set off all kinds of paranoid ideas. But also brought doubt that is was an intended hack and perhaps my code is flawed, allowing an innocent user could “trip the alarm”.
The idea about having more than one form open in different browser tabs does allow this to happen without any “funny business” going on. It makes sense that the last form viewed overwrites the sessions for the previous one, so if the previous one is then submitted, it fails the security check.
When I tested myself, that is exactly what happened, so I believe that is what the user did.

On another site, I do have a system like that. Any funny business is detected and Boof!, They get blocked automatically, but with a option for redemption if a legitimate explanation can be given.
But where there is the possibility for false positives, I don’t want to be too harsh. It would seem a dis-service to my client if I treat their visitors badly and give a bad UX (their site, not mine).

In this case they would not be able contact me, as I am only contactable through one of the forms, which they would be locked out from. But the person they were trying to contact with the form does also have a phone number on their profile, so they had that as an alternative. It is also possible they could just get frustrated with being locked out of the form and give up. Though I don’t see any attempt to access it again. That brings another possibility, that they don’t even realise the message was not sent, since there was no error message, they currently just get dumped back on the homepage.

One of the main points of the form was not to. Otherwise I would save myself the trouble of making forms, have mailto: links and everyone gets spammed.
I think for now I’ll go with the quick fix of displaying a deliberately vague error message, so in future, at least they will know the submission did not go through.
Hopefully this was a freak occurrence of those perticular circumstances and will not be an everyday thing.
But in the long term I will try to dream up a way to improve the system and remove the possibility of this happening.


An update on this.

I did do this, but then never got around to uploading it to the host server.
Then yesterday I got another report showing the same problem. Again the IP was local (not the same). I checked the access logs again to track the behaviour of that IP and I guess they did the same thing as the other one, opening more than one instance of the form.
Anyway, I set to work last night to fix it and avoid normal users from tripping my security alarms.
There are actually a few things that the form saves to the session, not just the token. So what I did was put all those things in an array. I create a random string as a unique ID for any instance of the form, then put the array to a session value with the ID string as the key. The ID is passes with the form too in a hidden field, so on processing, it can retrieve its own session data and check its validity, without being confused by sessions form another instance of the form.
I tested it, and it appears to work.
Checking the database this morning, I see a real user has submitted a new message late last night. So it’s not broke.
Then, coincidently (I think) when I checked my emails, I had two reports of hack attempts on the form early in the morning from a Russian bot. It actually got the token correct, but failed on three other tests have in place.
That being the first confirmed genuine hack attempt on the form, which surprises me with the site having been live since late February.

Hi Sam, I was going to suggest storing form token data in the session by form id but good you figured that out. Another thing I do is to check the time elapsed since the form is rendered until it is submitted. A bot will fill in a form a lot faster than a user, so there you have another criteria for determining authenticity.
Hope that helps.

1 Like

I have that already, that is one of the tests the Russian bot failed on. The first time it took 0 seconds, the second time it took 1.

Ha, then you seem to have a game here! Great opportunity to up-skill on security. I will be following this thread.
I have sometimes wondered if it would be a good idea to enable the form via JavaScript. Something I’m not sure is if bots get JavaScript running when they visit a page. Although the solution would mean doing away with users that have no JavaScript enabled which is not good.

They should not have got a second chance. They must have cleared to a new session, which won’t be too difficult.
But when I am confident I have a robust system that will not catch innocent users, then I can up the game a bit and automatically black-list IPs from the whole site after the first offence. I will just see how it goes after this latest change.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.