Forum OpenACS Development: Blocking access to login based on repetitive hits by ip address? (Again!)

I started a new thread so as not to interrupt the discussion on Gustaf's excellent throttling module.

In summary, here is my original question:

My web page stats (of my personal site) show something quite interesting.

/register/ receives over 4000 hits a month, but I have less than 20 registered users in over 1 year.

And my site allows anonymous comments, so it's not because people are being thrown to /register/ and leaving.

So I'm assuming that people are hitting my registration page with automated username/password robots trying to brute force their way in.

My proposed solution is to detect > x hits to /register/ from an individual ip address within y minutes, and block that ip for y hours.

My needs were somewhat simpler than Gustaf's, so here's what I came up with.

I basically nsv_incr a global nsv with the peeraddr as the key, then I have a scheduled proc decrementing the number of tries every 5 minutes.

If the try count hits zero then the key is nsv_unset.

in a -proc.tcl somewhere:

ad_proc decrease_registerips {} {} {
    foreach key [nsv_array names registerips] {
        set tries [nsv_incr registerips $key -5]
        if {$tries < 1} {
            nsv_unset registerips $key
in a -init.tcl somewhere:
nsv_set registerips "" 0

ad_schedule_proc 300 decrease_registerips
to create the nsv and schedule the cleanup. Finally, put this in acs-subsite/www/register/index.tcl:
set user_ip [ad_conn peeraddr]

# get peer address from ad_conn or header if behind a local proxy
if {[string match $user_ip ""]} {
    set user_ip [lindex [ns_set iget [ns_conn headers] x-forwarded-for] end]

if {[nsv_exists registerips $user_ip]} {
    set tries [nsv_incr registerips $user_ip]
} else {
    nsv_set registerips $user_ip 0
    set tries 0

if {$tries > 5} {
    ad_return_error "Access error" "Too many loads of /register. Please try again later"
You will need to adjust if you are behind a proxy not on You can also add this code to other pages - you should then probably increase the allowed count (or use a seperate nsv).

I think something along these lines would be useful in the standard acs-subsite, with the number of tires per 5 minutes as a parameter (and more robust proxy detecting).


I believe you should move the code from index.tcl to user-login.tcl.  An automated hackbot can skip index.tcl and hack away at user-login.tcl.

Also there isn't any danger in index.tcl being retrieved thousands of times, the danger is in login attempts via user-login.tcl.

I would put this code into the failed login portion(s) of user-login.tcl.  That way successful logins do not affect your counter, minimizing your chances for accidently blocking users that share an IP.

I'd check your robots.txt file first.