我有一个网站,用户使用AJAX将消息提交到名为like.php
的文件。在此文件中,用户消息将提交给数据库,然后将链接发送回用户。在我的Javascript代码中,我禁用了用户在提交AJAX请求时键入的文本框。
唯一的问题是,恶意用户可以不断向like.php
发送POST请求并充斥我的数据库。所以我想实施简单的防洪保护。
我真的不想让另一个数据库表记录用户IP等麻烦...好像他们充斥着我的网站会有很多数据库读/写速度慢下来。我想过使用会话,比如有一个包含时间戳的会话,每次将数据发送到like.php
时都会检查,如果当前时间在时间戳之前让他们将数据添加到数据库,否则发送一个错误并阻止他们。如果允许他们在数据库中输入内容,请使用新的时间戳更新其会话。
感谢您的帮助。 :)
答案 0 :(得分:7)
会话是最容易实现的,并且开销也最小。您可以在会话中存储两位数据,最后一篇文章的时间戳,和该帖子来自的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
答案 1 :(得分:5)
使用令牌。您生成令牌并将其添加到发起请求的页面。在like.php
中,您验证请求是否包含有效令牌,这意味着它来自您的网页而不是外部直接POST。
答案 2 :(得分:3)
另一种方法是使用jQuery将隐藏的表单输入写入页面(调用like.php)。机器人将不会使用javascript,因此您的隐藏表单字段将不存在。
检查隐藏字段(为其指定值和名称),如果存在,则使用请求命中数据库。
另一种方式;将隐藏元素编码到页面中(<input style='display:none;' name='nospam' value='' />
)。机器人将自动填充表单中的每个字段,因此您只需检查该字段是否已填充 - 用户无法看到它,因此如果您有内容,则您知道它是机器人。
使用jQuery设置样式(display:none;)...再次,机器人不会看到jQuery,所以它会认为这是一个合法的表单输入。
您可能需要为用户指定“此页面需要运行javascript”通知。一些替代建议。毕竟 - 你说'简单';)
答案 3 :(得分: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 *");
}
答案 4 :(得分:2)
我做了一个脚本来处理核心请求(没有会话请求或其他没有调用核心的请求)。如果你看看谷歌你会发现脚本/类会因为每次高负荷而杀死你的服务器。事实上,许多人使用SESSION,也许还有SQL /数据库,这将使您获得作为服务器杀手的防洪保护。此外,SESSION需要Cookie(或GET SID),以便您可以轻松地操作SESSION获取新的SESSION ID。
我的功能是基于文本的,并且操作简单。不好的是,你可能不得不使用CronJob来不时删除ips。与其他脚本相比,它的速度提高了10倍(并且比会话节省了更多)。
我不知道它是否真的有用。 ;) 您可能希望将rpm值更改为less或/以及200 req。我的设置禁止机器人在&lt; = 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();
它可能提供更多功能,但所有合法用户都不会使用servertime。 ;)
答案 5 :(得分:0)
我想过使用会话,比如 有一个包含a的会话 每次都要检查的时间戳 他们将数据发送到like.php
这不会阻止机器人,因为他们可以接收和发送用户所做的相同的cookie。
您应该让用户登录到这样的系统。似乎值得保护访问。您还可以考虑限制每个IP每分钟的帖子,但多个机器人仍然可以发送许多垃圾邮件。
如果您不想实施登录,那么许多网站都会使用captcha来尝试减少此类尝试。
答案 6 :(得分:0)
如果您想停止充斥搜索页面,可以这样尝试:
$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'];
因此,如果您的访问者在例如10次以下搜索2秒他会被拦住!