11

我有一个网站,用户使用 AJAX 将消息提交到名为like.php. 在此文件中,用户消息被提交到数据库,然后将链接发送回用户。在我的 Javascript 代码中,我禁用了用户在提交 AJAX 请求时输入的文本框。

唯一的问题是,恶意用户可以不断地向我的数据库发送 POST 请求like.php并淹没我的数据库。所以我想实现简单的防洪。

我真的不想要另一个数据库表记录用户 IP 等的麻烦......好像他们正在淹没我的网站,会有很多数据库读/写会减慢它的速度。我考虑过使用会话,比如有一个包含时间戳的会话,每次发送数据时都会检查该时间戳,like.php如果当前时间在时间​​戳之前,让他们将数据添加到数据库中,否则会发出错误并阻止它们。如果允许他们在数据库中输入某些内容,请使用新的时间戳更新他们的会话。

你怎么看?这是最好的方法还是有更简单的选择?

谢谢你的帮助。:)

4

7 回答 7

7

Session 是最容易做到这一点的,而且开销也最小。您可以在会话中存储两位数据,最后一个帖子的时间戳,以及帖子来自的 ip。以下是您检查合法性的方法:

session_start();
if(isset($_SESSION['ip']) && $_SESSION['last_post'] + MININTERVAL < time()) die('too early');

$_SESSION['last_post'] = time();
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
// store the message
于 2010-06-11T23:23:05.030 回答
5

使用令牌。您生成令牌并将其添加到发起请求的页面。在like.php您验证请求是否包含有效令牌,这意味着它来自您的页面,而不是直接发布的外部页面。

于 2010-06-11T22:42:07.117 回答
3

好吧,我制作了一个脚本来仅针对核心请求处理它(没有会话请求或其他不调用核心的请求)。如果你看看谷歌,你会发现脚本/类会因为每次高负载而杀死你的服务器。事实上,许多人使用 SESSION 并且可能还使用 SQL/Database 将使您获得作为服务器杀手的泛洪保护。此外,SESSION 需要 Cookie(或 GET SID),因此您可以轻松地操纵 SESSION 以获得新的 SESSION ID。

我的功能是基于文本的,并且做一个简单的处理。坏事是您可能不得不不时使用 CronJob 删除 ips。与其他脚本相比,它的速度大约快 10 倍(并且比会话节省更多)。

我不知道它是否真的有用。;) 您可能希望将 rpm 值更改为 less 或/以及 200 req。我的设置是禁止机器人在 <=6 秒内执行间隔请求。

<?php
function ht_request_limiter() {
    if (!isset($_SERVER['REMOTE_ADDR'])) { return; } // Maybe its impossible, however we check it first
    if (empty($_SERVER['REMOTE_ADDR'])) { return; } // Maybe its impossible, however we check it first
    $path = '/your/path/ipsec/'; // I use a function to validate a path first and return if false...
    $path = $path.$_SERVER['REMOTE_ADDR'].'.txt'; // Real file path (filename = <ip>.txt)
    $now = time(); // Current timestamp
    if (!file_exists($path)) { // If first request or new request after 1 hour / 24 hour ban, new file with <timestamp>|<counter>
        if ($handle = fopen($path, 'w+')) {
            if (fwrite($handle, $now.'|0')) { chmod($path, 0700); } // Chmod to prevent access via web
            fclose($handle);
        }
    }
    else if (($content = file_get_contents($path)) !== false) { // Load existing file
        $content = explode('|',$content); // Create paraset [0] -> timestamp  [1] -> counter
        $diff = (int)$now-(int)$content[0]; // Time difference in seconds from first request to now
        if ($content[1] == 'ban') { // If [1] = ban we check if it was less than 24 hours and die if so
            if ($diff>86400) { unlink($path); } // 24 hours in seconds.. if more delete ip file
            else {
                header("HTTP/1.1 503 Service Unavailable");
                exit("Your IP is banned for 24 hours, because of too many requests.");
            }
        }
        else if ($diff>3600) { unlink($path); } // If first request was more than 1 hour, new ip file
        else {
            $current = ((int)$content[1])+1; // Counter + 1
            if ($current>200) { // We check rpm (request per minute) after 200 request to get a good ~value
                $rpm = ($current/($diff/60));
                if ($rpm>10) { // If there was more than 10 rpm -> ban (if you have a request all 5 secs. you will be banned after ~17 minutes)
                    if ($handle = fopen($path, 'w+')) {
                        fwrite($handle, $content[0].'|ban');
                        fclose($handle);
                        // Maybe you like to log the ip once -> die after next request
                    }
                    return;
                }
            }
            if ($handle = fopen($path, 'w+')) { // else write counter
                fwrite($handle, $content[0].'|'.$current .'');
                fclose($handle);
            }
        }
    }
}

编辑:我测试请求时间的方法是使用 microtime 并模拟 10'000 个用户。我问谷歌并测试(例如)http://technitip.net/simple-php-flood-protection-class

所以我不知道那里应该简单吗?您一次有大约 3 个 SQL 请求,例如:

$this -> user_in_db($ip))
$this->user_flooding($ip);
$this->remove_old_users();

它可能提供更多功能,但所有合法用户都白白使用服务器时间。;)

于 2012-05-04T16:13:04.253 回答
3

另一种方法是使用 jQuery 将隐藏的表单输入写入页面(调用 like.php)。机器人不会使用 javascript,因此您的隐藏表单字段将不存在。

检查隐藏字段(为其分配值和名称),如果存在,则使用请求访问数据库。

另一种方式; 将隐藏元素编码到页面中 ( <input style='display:none;' name='nospam' value='' />)。机器人将自动填充表单中的每个字段,因此您只需检查该字段是否已填充 - 用户看不到它,因此如果您在那里有内容,您就知道它是机器人。

使用 jQuery 设置样式 (display:none;) ......再一次,机器人不会看到 jQuery,所以它会认为这是一个合法的表单输入。

您可能希望在某处为用户指定“此页面需要运行 javascript”通知。一些替代建议。毕竟 - 你说'简单';)

于 2012-04-16T00:53:20.007 回答
3

您不需要浏览整个记录文件。反而:

<?php
define("FLOODPOOL", ".");
define("FLOODPOOL_LIMIT", 30);
define("FLOODPOOL_DURATION", 60 * 60 * 24);
define("FLOODPOOL_AUTOCLEAN", true);

// Record and check flood.
// Return true for hit.
function floodpool_check($id){
    $fp = fopen(FLOODPOOL . DIRECTORY_SEPARATOR . 'fp_' . basename($id), 'a+');
    fwrite($fp, pack('L', time()));
    if(fseek($fp, -4 * FLOODPOOL_LIMIT, SEEK_END) === -1) {
        return false;
    }
    $time = reset(unpack('L', fread($fp, 4)));
    fclose($fp);
    if(time() - $time < FLOODPOOL_DURATION) {
        if(FLOODPOOL_AUTOCLEAN){
            @floodpool_clean();
        }
        return true;
    }
    return false;
}


// Clean the pool.
function floodpool_clean(){
    $handle = opendir(FLOODPOOL);
    while(false!==($entry=readdir($handle))){
        $filename = FLOODPOOL . DIRECTORY_SEPARATOR . $entry;
        if(time() - filectime($filename) > FLOODPOOL_DURATION && substr($entry, 0, 3) === 'fp_'){
            unlink($filename);
        }
    }
    closedir($handle);
}

使用示例:

if(floodpool_check($_SERVER['REMOTE_ADDR'])){
    header("HTTP/1.1 429 Too Many Requests");
    exit("Hit some *");
}
于 2015-03-30T08:13:38.267 回答
1

如果您想停止淹没搜索页面,可以这样尝试:

$flood_protection_interval = 2;
session_start();
if(
    isset($_SESSION['ip']) && 
    $_SESSION['counter'] > 10 &&
    $_SESSION['last_post'] + $flood_protection_interval > time()
    ){
        // $_SESSION['counter'] = 0; // Use this if you want to reset counter
        die("<pre>\n\n\n\t<b>FLOOD PROTECTION</b>");
}
$_SESSION['counter']++;
$_SESSION['last_post'] = time();
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];

因此,如果您的访问者在 2 秒内搜索 10 次,他将被阻止!

于 2016-04-27T15:30:43.070 回答
0

我考虑过使用会话,比如有一个包含时间戳的会话,每次将数据发送到 like.php 时都会检查该时间戳

这不会阻止机器人,因为它们可以接收和发送与用户相同的 cookie。

您真的应该让用户登录到这样的系统。似乎值得保护访问。您还可以考虑限制每个 ip 每分钟的帖子,但多个机器人仍然可以发送许多垃圾邮件。

如果您不想实现登录,那么许多网站都会使用验证来尝试减少此类尝试。

http://www.phpcaptcha.org/

于 2010-06-11T22:32:12.257 回答