Защита със записване на броя презареждания на всяко IP

Hous

Registered
Гледам този код:
Код:
<?php
session_start();
?>

{{H1:PHP: Reload count}}

<nowiki>
<?php
if (empty($_SESSION['counter']))
	$_SESSION['counter'] = 1;
else
	$_SESSION['counter']++;
?>
</nowiki>

You've (re-)loaded this page 
<?php echo $_SESSION['counter']; ?> times. 
Press F5 to reload it again.

И се чудя как да стане да брои рефрешите на всяко ИП а не по сесия
и да ги записва в дб за определено време ,примерно 1 ден
за да се постави лимит на презарежданията за определено време пример:
ip 89.215.123.123 презарежда страницата 10 пъти в рамките на 5 секунди
и да му изпише съобщение Anty flood protection ,please wait 1min and try reloading web page.

Някой може ли да помогне?
 
Просто при зареждане на страницата взимаш ИПто на потребителя, създаваш си нов записв в таблицата с ИПтата ако няма такъв и му слагаш 1 за зареждания. При следващото зареждане вече ще има подобен запис, затова просто увеличаваш броя на презарежданията с 1.
 
Да на теория го имам ,въпроса е как да стане в скриптов вариянт.
Доста време ще се помъча да го докарам и накрая сигурно пак няма да работи,АКО някой даде поне 50% от идеята във скрипт ще съм благодарен. :)
 
Не знам дали съм разбрал ,но може да е нещо подобно.

Таблица : table
Полета : IP,count(default 0)

Code :

PHP:
<?php 
$yourip = $_SERVER['SERVER_ADDR'];

$check = mysql_query("SELECT * FROM table WHERE ip = '$yourip'") or die (mysql_error());
$cC = mysql_num_rows($check);

if ($cC > 0) {
    $d = mysql_fetch_array($check);
    $update = $d['count'] + 1;
    $dd = mysql_query("UPDATE table SET count = '$update' WHERE ip = '$yourip'")
}

else {
  $insert = mysql_query("INSERT INTO table(ip) VALUES('$yourip')") or die (mysql_error());
}

?>
 
Но аз не виждам смисъл в това , тъй като пак скрипта връща резултатът , а не го връща сървъра и тогава пак се трупа трафик и се товари машината.
Ако искаш да се справиш с ddos атаки то ти препоръчвам iptables
http://www.netfilter.org/projects/iptables/index.html
 
Идеята ми е да направя така,че всяко ип да се записва в таблица при посещението му където и да е в сайта,да стой самия запис 10мин примерно ,за да не се трупа таблицата излишно,и освен ип-то да се записва колко рефреша е направил (задържа ф5)примерно или нещо подобно и примерно ако направи повече от 10 заявки в рамките на 5 или по-малко секунди да го пренасочва към друг файл флоот.пхп или просто където и да е в сайта да получи съобщение Floot zashtita и в php едно exti;
на целия сайт


Идеята е да се предпазя от излишен трафик при презареждане на картинки/флаш файлове.

Самите презареждания трябва да се броят,а не броузването из сайта,не знам точно как да стане,иначе хоста си е защитен,въпроса е от към трафик да го огранича.

:)
 
Ето чрез сесии.

Във коментарите съм обяснил всичко, кое за какво служи.

Само чрез извикване на функцията Flood(); ще бъде достъпна (във всички файлове).

Също така не забравяй session_start();

Какво представлява:

- Брои колко опита си направил във зададено време, ако е true резултата, тогава потребитела се блокира от сайта за известно време.

- Ако потребитела е блокиран и продължи да дава рефреш или там каквото прави, времето му се увеличава според зададени условия.

- Потребителя се отблокира, ако времето на блока изтече (това вкл. горните две условия).

- Настройките на тези условия може да ги намериш в началото на файла, всичко съм обяснил с коментари.


Все пак ако е чрез SQL заявки, ще забавя значително, в сравнение, чрез сесиите. Ако все пак искаш ще ти направя и една чрез заявки и ще направя един тест за времето на изпълнение на двата кода. Вече стана доста късно и най - вероятно утре.

------------------------------

PHP:
<?php  
    
function Flood() {

/** Configs
 *  
 * Attempts - Count user refreshes
 * SecondLimit - The limit in time for the attempts (in seconds)
 * DoubleSecond - Increase the bann (if blocked) with any refresh (in seconds)
 * BanLimit - The time after the ban expired (in seconds)
 * 
 */
  
$Attempts = 5;
$SecondLimit = 5;
$DoubleSecond = 5;
$BanLimit = 10;
/** End config */


/** Getting current time (in seconds) */
$Now = time();

if(!isset($_SESSION['flood'])) 
{
$_SESSION['flood'] = 1;
$_SESSION['time'] = $Now;
}

else {
    
    /** Increment the flood */
      $_SESSION['flood'] = $_SESSION['flood']+1;

   /** Make the time options */
      $N = $Now - $_SESSION['time'];
      
      /** Checking for flood and creating the ban page*/
          if($_SESSION['flood'] >= $Attempts AND $N < $SecondLimit) {
             $_SESSION['time'] = $_SESSION['time'] + $DoubleSecond;
              exit ('<b>You flood the websait!</b>');
            }
            
        /** Clear flood and time if the user is not flooding */    
       elseif($_SESSION['flood'] >= $Attempts AND $N > $SecondLimit) {
              unset($_SESSION['time']);
              unset($_SESSION['flood']);
            }      
      
      /** Unban the user */
         elseif ($_SESSION['flood'] >= $Attempts AND $N > $BanLimit) {
             unset($_SESSION['flood']);
             unset($_SESSION['time']);
         }
}

}


---------------

Извикване:

PHP:
session_start();

Flood();

echo 'Hello world, this is my page';
?>
 
Само не разбрах дали :
PHP:
/** Unban the user */
         elseif ($_SESSION['flood'] >= $Attempts AND $N > $BanLimit) {
             unset($_SESSION['flood']);
             unset($_SESSION['time']);
         }
За да unbanne user-а трябва ли да стой определеното време (в $ban) на самия сайт,или примерно ако му задам 10 мин , той излиза от сайта и след 10 мин като се върне е отблокиран,или трябва да стой 10 мин на сайта за да го отчете сесията?

иначе кода изглежда лесен ,разбирам го като идея,има всичко кето искам ,САМО не ми харесва ,че е със сесии ,защото както споменаха в предната тема за флууд ако е бот,информацията за сесиите се пази в бисквитка и самия бот ако не си пази бисквитките скрипта става безполезен,и пак трафика ми ще лудне.



Благодаря много за опита,не обичам да чакам на готово но просто няма как да го преправя аз,е поне не и за 1-2 дни.
:)
 
Може и да не седи, на сесията не и пречи. Единствено ако затвори браузера тогава сесиите се нулират.
 
Значи BanLimit си изчислява времето според time() ,а не престоя за в страницата?
И това затваряне на браузъра и нулирането няма ли да е в полза на флуудера при положение,че е флуудил примерно и затвори браузъра ,веднага пак може да флууиди , или не?


Един опит със sql ще може ли за да препреча и на ботовете ?
 
Ban лимита се изчислява като от сегашното време изкараме времето в което е създаден банна (и ако продължи да дава рефреш това време се увеличава), това изчисление го вадим в една променлива $N. Сега ако $N е по голямо от зададения $BanLimit = 10, който е 10 (сек.) тогава махни банна.


-----
Сега ще ти направя и едно чрез заявки към MySQL.
-----

Само едно вмъкване на още едно условие във тази функция. Ако бота е от Google да не му блокира достапа, тоест да не го счита за флоодер. Не съм е тествал със гоогле бота, но би трябвало да работи:

PHP:
function Flood() {

/** Configs
 *  
 * Attempts - Count user refreshes
 * SecondLimit - The limit in time for the attempts (in seconds)
 * DoubleSecond - Increase the bann (if blocked) with any refresh (in seconds)
 * BanLimit - The time after the ban expired (in seconds)
 * 
 */
  
$Attempts = 5;
$SecondLimit = 5;
$DoubleSecond = 5;
$BanLimit = 10;
/** End config */


/** Getting current time (in seconds) */
$Now = time();

/** Getting the user agent */
$Agent = preg_replace("/[^A-Za-z0-9?!\s]/","", $_SERVER['HTTP_USER_AGENT']);
if (preg_match("/Google/", $Agent)) {
    return false;
} 

elseif(!isset($_SESSION['flood'])) 
{
$_SESSION['flood'] = 1;
$_SESSION['time'] = $Now;
}

else {
    
    /** Increment the flood */
      $_SESSION['flood'] = $_SESSION['flood']+1;

   /** Make the time options */
      $N = $Now - $_SESSION['time'];
      
      /** Checking for flood and creating the ban page*/
          if($_SESSION['flood'] >= $Attempts AND $N < $SecondLimit) {
             $_SESSION['time'] = $_SESSION['time'] + $DoubleSecond;
              exit ('<b>You flood the websait!</b>');
            }
            
        /** Clear flood and time if the user is not flooding */    
       elseif($_SESSION['flood'] >= $Attempts AND $N > $SecondLimit) {
              unset($_SESSION['time']);
              unset($_SESSION['flood']);
            }      
      
      /** Unban the user */
         elseif ($_SESSION['flood'] >= $Attempts AND $N > $BanLimit) {
             unset($_SESSION['flood']);
             unset($_SESSION['time']);
         }
}

}
 
Кажи ми с каква цел ти е подобен код? При добре конфигурирана машина нямаш нужда от подобни простотии. :)
 
Не прочете ли постовете ?
Идеята е да предотвратя излишен трафик.Машината е на платен хостинг и е перфектно конфигурирана,но въпроса е да не правя излишен трафик,защото имам новини и други подобни с големи картинки (както и галерия) и при задържане на рефреш за 1 мин ще направи едно 100мб трафик...
:lol:
 
Е.. в този случай отново ти прави трафик. 'щото се отваря страницата , фактически се трупа трафик. Въпреки, че не дърпаш/вкарваш в базата нещо. :)

Едит; И не, не съм чел всичките мнения само първото.
 
Направи си един файл DB.php , той ще ти е за връзка с базата данни, ще го include във всички файлове, който трябва да имаш тази връзка.


Времето на изпълнение, чрез сесии е:
0.0001

-----------

Времето на изпълнение, чрез тези заявки е:
0.01


DB.php

PHP:
<?php

class DB {
    private static $USER_HOST = 'localhost';
    private static $USER_NAME = 'root';
    private static $USER_PASS = 'password';
    private static $DB_NAME = 'flood';
    private static $ins = null;
    private $Err = array();
    
       private function __construct(){}
       private function __clone(){}
       
        public static function MyDB() {
            
            if(self::$ins == null)
                {
                try {
                $dbh = new PDO("mysql:host=".self::$USER_HOST.";dbname=".self::$DB_NAME, self::$USER_NAME, self::$USER_PASS, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
                $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                }  catch (Exception $PDOER) {
                        die('The connection fail');
                    }
                       return self::$ins = $dbh;            
                }
            return self::$ins;
        }

}

?>


--------------------------------------------------

Направи си един файл: delete.php

Него го зареждай, като зададеш един cronjob към файла, задай му да се изпълнява на всяка 1 минута примерно или на всеки час (няма значение), това ще ти изчиства базата данни от излишните записи.


delete.php

PHP:
<?php

include ('DB.php');

/** The maximum time for the ban users (in sec) */
$TimeDelete = 60; 


$DB = DB::MyDB();

$Now = time();

$Result = $DB -> query("SELECT `id`,`ban` FROM `flood`");
while($Ban = $Result -> fetch(PDO::FETCH_ASSOC)) {

$Del = $Now - $Ban['ban'];
$Id = $Ban['id'];

if($Del > $TimeDelete) {
$DB -> query("DELETE FROM `flood` WHERE `id` = '$Id' ");
    }

}

?>

-------------------------------------------------

Ето и самата функция:

PHP:
<?php

include ('DB.php');

function Flood() {
        
    /** Configs
 *  
 * Attempts - Count user refreshes
 * SecondLimit - The limit in time for the attempts (in seconds)
 * DoubleSecond - Increase the bann (if blocked) with any refresh (in seconds)
 * BanLimit - The time after the ban expired (in seconds)
 * 
 */
  
$Attempts = 5;
$SecondLimit = 5;
$DoubleSecond = 5;
$BanLimit = 10;
/** End config */


/** Getting current time (in seconds) */
$Now = time();
       


        
        
        /** Getting the user agent */
        $Agent = preg_replace("/[^A-Za-z0-9?!\s]/","", $_SERVER['HTTP_USER_AGENT']);
        if (preg_match("/Google/i", $Agent)) {
            return false;
        } 
        
        
        /** Check if the user IP is valid */
        if(!filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP)) {
           exit('YOUR IP IS NOT VALID');
        }
           
        
        
        
            $Ip = $_SERVER['REMOTE_ADDR'];
   
            $DB = DB::MyDB();
      
            $IpCheck = $DB -> prepare("SELECT `ip`, `refresh`, `ban` FROM flood WHERE `ip` = :ip LIMIT 1");             
            $IpCheck -> bindParam(':ip', $Ip, PDO::PARAM_STR);
            $IpCheck -> execute();

            $Result = $IpCheck -> fetch(PDO::FETCH_ASSOC);
            
           
            
            
             if(!empty($Result)) {
                   
            $Refresh = $Result['refresh'] + 1;
                      
            $IpUpdate = $DB -> prepare("UPDATE `flood` SET `refresh` = :refresh WHERE `ip` = :ip");             
            $IpUpdate -> bindParam(':ip', $Ip, PDO::PARAM_STR);
            $IpUpdate -> bindParam(':refresh', $Refresh, PDO::PARAM_INT);
                       
            $IpUpdate -> execute();
                
                
            $N = $Now - $Result['ban'];
              
             
             /** Checking for flood and creating the ban page*/
           if($Result['refresh'] >= $Attempts AND $N < $SecondLimit) {
          
                       $Ban = $Result['ban'] + $DoubleSecond;
                  
                        $IpInsert = $DB -> prepare("UPDATE `flood` SET `ban` = :ban WHERE `ip` = :ip");             
                        $IpInsert -> bindParam(':ip', $Ip, PDO::PARAM_STR);
                        $IpInsert -> bindParam(':ban', $Ban, PDO::PARAM_INT);
            
                        $IpInsert -> execute();
                  
                      return exit('You are blocked');
            
                    }
                
                /** Unban the user */
                if($Result['refresh'] >= $Attempts AND $N > $BanLimit) {
                        
                        $IpDelete = $DB -> prepare("DELETE FROM `flood` WHERE `ip` = :ip");
                        $IpDelete -> bindParam(':ip', $Ip, PDO::PARAM_STR);
                        $IpDelete -> execute();
                        
                       return true;
                        
                   }
  
            }
            
            else {
            
                /** Insert new record if the ip dosen't exist */
                
                $Refresh = 1;
              
                    $IpInsert = $DB -> prepare("INSERT INTO `flood` (`ip`, `ban`, `refresh`) VALUES (:ip, :ban, :refresh)");
                    $IpInsert -> bindParam(':ip', $Ip, PDO::PARAM_STR);
                    $IpInsert -> bindParam(':ban', $Now, PDO::PARAM_INT);
                    $IpInsert -> bindParam(':refresh', $Refresh, PDO::PARAM_INT);
                
                    $IpInsert -> execute();
            
                   return true;
            }
            
            
                
         
        
        
        
}

?>


-------------------------------------

Извикването става по същия начин, чрез Flood();


EDIT:

Забравих SQL - а:

[sql]CREATE TABLE IF NOT EXISTS `flood` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip` varchar(25) NOT NULL,
`ban` int(20) NOT NULL,
`refresh` int(2) NOT NULL,
PRIMARY KEY (`id`),
KEY `ip` (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=38 ;[/sql]
 
Ticketa каза:
Е.. в този случай отново ти прави трафик. 'щото се отваря страницата , фактически се трупа трафик. Въпреки, че не дърпаш/вкарваш в базата нещо. :)

Едит; И не, не съм чел всичките мнения само първото.
Разликата е,че ще му дам exit; и няма да извършва по нататъчни зареждания на картинки/sql заявки нищо...
:lol:
 
Иначе @eddy93 няма какво да кажа,освен едно голямо БЛАГОДАРЯ.
Работи перфектно кода,просто ,дано на някой друг му свърши работа,и да го ползва с удоволствие ,защото си е доста код и то написан специално за темата.
+1 без съмнение :)
 

Back
Горе