oracular (3) CGI::Application::Plugin::RateLimit.3pm.gz

Provided by: libcgi-application-plugin-ratelimit-perl_1.0-4_all bug

NAME

       CGI::Application::Plugin::RateLimit - limits runmode call rate per user

SYNOPSIS

         use CGI::Application::Plugin::RateLimit;

         sub setup {
           ...

           # call this in your setup routine to set
           my $rate_limit = $self->rate_limit();

           # set the database handle to use
           $rate_limit->dbh($dbh);

           # set the table name to use for storing hits, the default is
           # 'rate_limit_hits'
           $rate_limit->table('rate_limit_hits');

           # keep people from calling 'send' more often than 5 times in 10
           # minutes and 'list' more often than once every 5 seconds.
           $rate_limit->protected_modes(send => {timeframe => '10m',
                                                 max_hits  => 5
                                                },
                                        list => {timeframe => '5s',
                                                 max_hits  => 1
                                                });

           # you can also protect abstract actions, for example to prevent a
           # flood of failed logins
           $rate_limit->protected_actions(failed_login => {timeframe => '10s',
                                                           max_hits  => 2
                                                          });

           # call this runmode when a violation is detected
           $rate_limit->violation_mode('too_fast_buddy');

           # or, run this callback
           $rate_limit->violation_callback(sub { die(...) });

           # override the default identity function
           # ($ENV{REMOTE_USER} || $ENV{REMOTE_IP})
           $rate_limit->identity_callback(sub { ... });
         }

         # record a hit for an action (not needed for run-modes which are
         # handled automatically)
         $rate_limit->record_hit(action => 'failed_login');

         # check for a violation on an action and handle
         return $self->slow_down_buddy
           if( $rate_limit->check_violation(action => 'failed_login') );

         # revoke the most recent hit for this user, preventing it from
         # counting towards a violation
         $rate_limit->revoke_hit();

         # examine the violation in violation_mode or violation_callback:
         $mode   = $rate_limit->violated_mode;
         $action = $rate_limit->violated_action;
         $limits = $rate_limit->violated_limits;

DESCRIPTION

       This module provides protection against a user calling a runmode too frequently.  A typical use-case
       might be a contact form that sends email.  You'd like to allow your users to send you messages, but
       thousands of messages from a single user would be a problem.

       This module works by maintaining a database of hits to protected runmodes.  It then checks this database
       to determine if a new hit should be allowed based on past activity by the user.  The user's identity is,
       by default, tied to login (via REMOTE_USER) or IP address (via REMOTE_IP) if login info is not available.
       You may provide your own identity function via the identity_callback() method.

       To use this module you must create a table in your database with the following schema (using MySQL-
       syntax, although other DBs may work as well with minor alterations):

         CREATE TABLE rate_limit_hits (
            user_id   VARCHAR(255)      NOT NULL,
            action    VARCHAR(255)      NOT NULL,
            timestamp UNSIGNED INTEGER  NOT NULL,
            INDEX (user_id, action, timestamp)
         );

       You may feel free to vary the storage-type and size of user_id and action to match your usage.  For
       example, if your identity_callback() always returns an integer you could make user_id an integer column.

       This table should be periodically cleared of old data.  Anything older than the maximum timeframe being
       used can be safely deleted.

       IMPORTANT NOTE: The protection offered by this module is not perfect.  Identifying a user on the internet
       is very hard and a sophisticated attacker can work around these checks, by switching IPs or automating
       login creation.

INTERFACE

       The object returned from calling "$self->rate_limit" on your CGI::App object supports the following
       method calls:

   dbh
          $rate_limit->dbh($dbh);

       Call this to set the database handle the object should use.  Must be set in setup().

   table
          $rate_limit->table('some_table_name');

       Call this to determine the table to be used to store and lookup hits.  The default is 'rate_limit_hits'
       if not set.  See the DESCRIPTION section for the required table schema.

   protected_modes
           $rate_limit->protected_modes(send => {timeframe => '10m',
                                                 max_hits  => 5
                                                },
                                        list => {timeframe => '5s',
                                                 max_hits  => 1
                                                });

       Takes a list of key-value pairs describing the modes to protect.  Keys are names of run-modes.  Values
       are hashes with the following keys:

         timeframe - the timeframe to be considered for violations.  Values
         must be numbers followed by either 's' for seconds, 'm' for minutes
         or 'h' for hours.

         max_hits - how many hits to allow in the specified timeframe before
         triggering a violation.

   protected_actions
           $rate_limit->protected_actions(failed_login => {timeframe => '10s',
                                                           max_hits  => 2
                                                          });

       Specifies non-run-mode actions to protect.  These are arbitrary keys you can use with record_hit() and
       check_violation().  Takes the same data-structure as protected_modes().

   violation_mode
         $rate_limit->violation_mode('too_fast_buddy');

       Call to set a run-mode to call when a violation is triggered.  Either this or violation_callback must be
       set.

   violation_callback
           $rate_limit->violation_callback(sub { ... });

       Callback to call when a violation is detected.  Should either throw an exception or return the run-mode
       to run.  Called with the CGI::App object as its sole parameter.

   identity_callback
           $rate_limit->identity_callback(sub { ... });

       Call this to provide a customized mechanism for determining the identity of the user.  The default is:

         sub { $ENV{REMOTE_USER} || $ENV{REMOTE_IP} }

       You might consider adding in session-ID or a hook to your authentication system if it doesn't use
       REMOTE_USER.  Whatever you write should return a single scalar which is expected to be unique to each
       user.

   record_hit
         $rate_limit->record_hit(action => 'failed_login');

       Record a hit for an arbitrary action.  This is not needed for run-mode protection.  Takes the action name
       as an argument, which must match an action registered with protected_actions().

   check_violation
         return $self->slow_down_buddy
           if( $rate_limit->check_violation(action => 'failed_login') );

       Checks for a violation of a protected action.  This is not needed for run-mode protection.  Takes the
       action name as an argument, which must match an action registered with protected_actions().

       Returns 1 if a violation took place, 0 otherwise.

   revoke_hit
         $rate_limit->revoke_hit();

       Revokes the last hit for this user.  You might use this to prevent validation errors from counting
       against a user, for example.

   violated_mode
         $mode = $rate_limit->violated_mode;

       Returns the mode for the last violation, or undef if an action caused the violation.

   violated_action
         $mode = $rate_limit->violated_action;

       Returns the action for the last violation, or undef if an action caused the violation.

   violated_limits
         $limits = $rate_limit->violated_limits;

       Returns the hash-ref passed to protected_actions() or protected_modes() for the violated mode/action.

DATABASE SUPPORT

       I've tested this module with MySQL and SQLite.  I think it's likely to work with many other databases -
       please let me know if you try one.

SUPPORT

       Please send questions and suggestions about this module to the CGI::Application mailing-list.  To join
       the mailing list, simply send a blank message to:

         cgiapp-subscribe@lists.erlbaum.net

VERSION CONTROL

       This module is in a public Subversion repository at SourceForge here:

          https://svn.sourceforge.net/svnroot/html-template/trunk/CGI-Application-Plugin-RateLimit

BUGS

       I know of no bugs.  If you find one, let me know by filing a report on http://rt.cpan.org.  Failing that,
       you can email me at sam@tregar.com.  Please include the version of the module you're using and small test
       case demonstrating the problem.

AUTHOR

       Sam Tregar, sam@plusthree.com

       Copyright (C) 2006 by Sam Tregar

       This library is free software; you can redistribute it and/or modify it under the same terms as Perl
       itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.