Get Adobe Flash player

Php ile saldırıları önlemek

Php ile flood saldırılarından korunmak

<?php

// ----------------------------------------------------------------------------
//
// class.floodblocker.php - FloodBlocker class, ver.0.01 (April 15, 2005)
//
// Description:
//   Class allowing to protect the scripts from flooding and to prevent
//   automatic download of the site from single IP.
//
// Author:
//   Vagharshak Tozalakyan <<a href="mailto:vagh@armdex.com">vagh@armdex.com</a>>
//   This module was written by author on its leasure time.
//
// Warning:
//   This class is non commercial, non professional work. It should not have
//   unexpected results. However, if any damage is caused by this class the
//   author can not be responsible. The use of this class is at the risk of
//   the user.
//
// Requirements:
//   PHP >= 4.1.0
//
// ----------------------------------------------------------------------------
// Errors and warnings

define ( 'E_TMP_DIR',    'Incorrect temprorary directory specified.' );
define ( 'E_IP_ADDR',    'Incorrect IP address specified.' );
define ( 'E_LOG_FILE',   'Log file access error! Check permissions to write.' );
define ( 'E_CRON_FNAME', 'The name of cron file must begin with dot.' );
define ( 'E_CRON_FILE',  'Cron file access error! Check permissions to write.' );
define ( 'E_CRON_JOB',   'Unable to perform the cron job.' );
// Class definition

class FloodBlocker
{

  // The directory where log files will be saved. Must have permissions to write.
  var $logs_path;

  // IP address of current connection. REMOTE_ADDR will be used by default.
  var $ip_addr;

  // An associative array of [$interval=>$limit] format, where $limit is the
  // number of possible requests during $interval seconds.
  var $rules;

  // The name of the cron file. Must begin with dot. Default filename is '.time'.
  var $cron_file;

  // Cron execution interval in seconds. 1800 secs (30 mins) by default.
  var $cron_interval;

  // After how many of seconds to consider a file as old? By default the files
  // will consider as old after 7200 secs (2 hours).
  var $logs_timeout;
  /*
    Description:
      Class constructor.
    Prototype:
      void FloodBlocker ( string logs_path, string ip = '' )
    Parameters:
      logs_path - the directory where log files will be saved
      ip - the ip address of the current connection,
           $_SERVER['REMOTE_ADDR'] will be used if ip=''
  */
  function FloodBlocker ( $logs_path, $ip = '' )
  {

    if ( ! is_dir ( $logs_path ) )
      trigger_error ( E_TMP_DIR, E_USER_ERROR );

    $logs_path = str_replace ( '\\', '/', $logs_path );
    if ( substr ( $logs_path, -1 ) != '/' )
      $logs_path .= '/';

    $this->logs_path = $logs_path;

    if ( empty ( $ip ) )
      $ip = $_SERVER['REMOTE_ADDR'];

    $ip = ip2long ( $ip );
    if ( $ip == -1 || $ip === FALSE )
      trigger_error ( E_IP_ADDR, E_USER_ERROR );

    $this->ip_addr = $ip;

    $this->rules = array ( );
    $this->cron_file = '.time';
    $this->cron_interval = 1800;  // 30 minutes
    $this->logs_timeout = 7200;  // 2 hours

  }
  /*
    Description:
      Used to check flooding. Generally this function acts as private method
      and will be called internally by public methods. However, it can be called
      directly when storing logs in db.
    Prototype:
      bool RawCheck ( array &info )
    Parameters:
      info - $interval=>$time, $interval=>$count array
    Return:
      FALSE if flood detected, otherwise - TRUE.
  */
  function RawCheck ( &$info )
  {

    $no_flood = TRUE;

    foreach ( $this->rules as $interval=>$limit )
    {
      if ( ! isset ( $info[$interval] ) )
      {
        $info[$interval]['time'] = time ( );
        $info[$interval]['count'] = 0;
      }

      $info[$interval]['count'] += 1;

      if ( time ( ) - $info[$interval]['time'] > $interval )
      {
        $info[$interval]['count'] = 1;
        $info[$interval]['time'] = time ( );
      }

      if ( $info[$interval]['count'] > $limit )
      {
        $info[$interval]['time'] = time ( );
        $no_flood = FALSE;
      }

      // The following two lines can be used for debugging
      // echo $info[$interval]['count'].'  ';
      // echo $info[$interval]['time'].'<br>';

    }  // foreach

    return $no_flood;

  }
  /*
    Description:
      Checks flooding. Must be called after setting up all necessary properties.
    Prototype:
      bool CheckFlood ( )
    Return:
      FALSE if flood detected, otherwise - TRUE.
  */
  function CheckFlood ( )
  {

    $this->CheckCron ( );

    $path = $this->logs_path . $this->ip_addr;

    if ( ! ( $f = fopen ( $path, 'a+' ) ) )
      trigger_error ( E_LOG_FILE, E_USER_ERROR);

    flock ( $f, LOCK_EX );

    $info = fread ( $f, filesize ( $path ) + 10 );
    $info = unserialize( $info );

    $result = $this->RawCheck ( $info );

    ftruncate ( $f, 0 );
    fwrite ( $f, serialize( $info ) );
    fflush ( $f );

    flock($f, LOCK_UN);

    fclose($f);

    return $result;

  }
  /*
    Description:
      Checks the cron file and calls CronJob() to delete old entries from logs
      directory if the time-out is reached.
    Prototype:
      void CheckCron ( )
  */
  function CheckCron ( )
  {

    if ( substr ( $this->cron_file, 0, 1 ) != '.' )
    {
      trigger_error ( E_CRON_FNAME, E_USER_WARNING );
      return;
    }

    $path = $this->logs_path . $this->cron_file;

    if ( ! ( $f = fopen ( $path, 'a+' ) ) )
    {
      trigger_error ( E_CRON_FILE, E_USER_WARNING );
      return;
    }

    flock ( $f, LOCK_EX );

    $last_cron = fread ( $f, filesize ( $path ) + 10 );
    $last_cron = abs ( intval ( $last_cron ) );

    if ( time ( ) - $last_cron > $this->cron_interval )
    {
      $this->CronJob ( );
      $last_cron = time ( );
    }

    ftruncate ( $f, 0 );
    fwrite ( $f, $last_cron );
    fflush ( $f );

    flock ( $f, LOCK_UN );

    fclose ( $f );

  }
  /*
    Description:
      Deletes all old files from logs directory, except the files starting
      with dot.
    Prototype:
      void CronJob ( )
  */
  function CronJob ( )
  {

    $path = $this->logs_path;

    if ( ! ( $dir_hndl = opendir ( $this->logs_path ) ) )
    {
      trigger_error ( E_CRON_JOB, E_USER_WARNING);
      return;
    }

    while ( $fname = readdir ( $dir_hndl ) )
    {
      if ( substr( $fname, 0, 1 ) == '.' )
        continue;
      clearstatcache ( );
      $ftm = filemtime ( $path . $fname );
      if ( time ( ) - $ftm > $this->logs_timeout )
        @unlink ( $path . $fname );
    }

    closedir ( $dir_hndl );

  }

}  // end of class definition

 

/*
  $flb = new FloodBlocker ( 'example/tmp-ips/' );
  $flb->rules = array ( 10=>5 );
  $res = $flb->CheckFlood ( );
  if ( $res )
    echo 'Succeed!';
  else
    die ( 'Too many requests! Please try later.' );
*/

?>

Kullanım Şekli


<?php

  // Place flood protection code at the top of the script you want to protect.
  // You can write protection code into separate file and include it in every
  // page of your site.

  // Sample protection code starts here...

  // Include the class definition module.

  require_once ( '../class.floodblocker.php' );

  // In the following line write the full path to temporary directory in which
  // you want to store flood counters. It is good idea to create such folder
  // somewhere outside your documents directory, to make it unaccessable from Web.
  // Don't forget that the directory must have permissions to write files in it.
  // IMPORTANT!
  // All files in this folder (except those that start with dot, e.g.'.htaccess')
  // will be deleted by FloodBlocker, so don't keep anything there.

  $flb = new FloodBlocker ( 'tmp-ips/' );

  // Create as many rules as you want...

  $flb->rules = array (
    10=>10,    // rule 1 - maximum 10 requests in 10 secs
    60=>30,    // rule 2 - maximum 30 requests in 60 secs
    300=>50,   // rule 3 - maximum 50 requests in 300 secs
    3600=>200  // rule 4 - maximum 200 requests in 3600 secs
  );

  // At last call CheckFlood(), it will return FALSE if flood detected on any
  // of specified rules.

  if ( ! $flb->CheckFlood ( ) )
    die ( 'Too many requests! Please try later.' );

  // ... that's all. Enjoy!

?>

<html>
<head>
<title>The title of my page...</title>
</head>
<body bgcolor="#cccccc">
<h1>Welcome to my page...</h1>
No flood was detected if you see the contents of this page...
</body>
</html>

Leave a Reply