使用php / mysql禁止IP

时间:2010-06-06 22:23:51

标签: php mysql

我希望能够通过IP禁止用户。我的想法是将一个IP列表保存为BannedIPs表中的行(IP列将是一个索引)。

要根据表检查用户的IP,我将为每个会话保留一个名为$ _SESSION ['IP']的会话变量。如果在任何请求中,$ _SESSION ['IP']与$ _SERVER ['REMOTE_ADDR']不匹配,我将更新$ _SESSION ['IP']并检查BannedIPs表以查看IP是否被禁止。 (标志也将保存为会话变量,指定用户是否被禁止)

以下是我想知道的事情:

  1. 这听起来像是一个关于速度和安全性的好策略(除了更改IP,编辑或使用代理之外,有人能够以某种方式绕过IP禁令吗?)< / LI>
  2. 构造一个检查行是否存在的mysql查询的最佳方法是什么?也就是说,查询数据库以查看是否存在具有某个IP的行的最佳方法是什么(检查它是否被禁止)?
  3. 我应该将IP保存为整数还是字符串?
  4. 请注意......

    • 我估计在数据库中存储了1,000-10,000个被禁止的IP。
    • $ _ SERVER ['REMOTE_ADDR']是发送当前请求的IP。

5 个答案:

答案 0 :(得分:6)

首先,我建议不要使用MySQL和PHP来执行此操作。 Apache有一个Deny指令来禁止IP地址,最终将比自己开发的解决方案更好。

您可以轻松创建后端以查看&amp;编辑包含所有条目的.htaccess文件。

以下是一个禁止2个IP地址的示例(对于那些想知道的人来说是谷歌DNS服务器),如果被禁止则显示自定义页面...

Order Allow,Deny
Deny from 8.8.8.8
Deny from 8.8.4.4
Allow from all

ErrorDocument 403 /access_is_denied.htm

此功能由Apache 2.2中的mod_authz_host提供。有关每个指令的更多信息,请参阅Apache's mod_authz_host Documentation Page


话虽如此:

  1. 当用户的IP在$_SESSION['IP']中始终可用时,为什么会有$_SERVER['REMOTE_ADDR']?我能看到的唯一原因是保存到数据库的行程......但是如果你将这个IP添加到你的禁令列表中,他仍然可以访问,直到他的会话到期。

  2. 如果您确实仍想使用数据库,请将IP地址存储为INT(或2 BIGINT列(如果您要支持IPv6)。它们占用的空间少于字符串,比较快。

  3. 至于它的安全性......他们可以通过代理来绕过禁令。如果您希望收到响应,则在数据包中欺骗IP地址是完全没用的。

答案 1 :(得分:2)

  1. 是的,通过HTTP标头欺骗。
  2. Select Count(*) from bannedIPs where ip = $input,如果返回0,则不会禁止IP。
  3. 我会用字符串。
  4. 一般情况下,我建议您记住,您的站点可能被一台路由器后面的许多计算机访问,这意味着所有用户都会显示相同的IP。你禁止一个,你禁止他们。我决心通过电子邮件和其他方式禁止。此外,我想说,那些伤害你网页的人不会被ip禁令或其他手段阻止。考虑到这一点,始终保护自己免受XSS,sql注入等常见的待遇。

答案 2 :(得分:1)

回答你的第3个问题:

您可能需要处理IPv6以及IPv4,因此您的数据结构需要允许128位地址值。

答案 3 :(得分:1)

10.000条目是MySQL的简单游戏。只需将索引设置为正确,此金额就没有问题。

也许您应该考虑使用白名单而不是黑名单,这可能会减少您的IP地址列表?

只要用户不在旋转代理后面,您的策略就会起作用。即通过AOL客户端访问网站的AOL用户将具有不同的IP地址,因为他们的请求来自不同的代理服务器。通常这不是问题。

用户的IP地址保存在您的会话中($ _SESSION ['IP']),该会话通常存储在您的服务器上,因此足够安全。

以下是检查表中条目的示例代码:

$raw = mysql_query ("SELECT ip FROM ip_blacklist WHERE ip = '" . mysql_escape_string(getenv('REMOTE_ADDR')) . "' LIMIT 0,1");
if ( mysql_num_rows ($raw) ) {
 // match found
}
else {
 // no match found
}

您可以修改它以仅搜索IP的一部分。即,而不是192.168.0.1,您可以搜索192.168.0。%:

… WHERE ip LIKE '192.168.0.%' …

这使您可以过滤小型网络,而不是定义所有IP地址。

使用整数通常是最好的方法,尤其是在使用数据库和范围时。 如果您想更好地理解/读取数据,字符串会更好。

答案 4 :(得分:1)

  1. http://www.rubyrobot.org/article/protect-your-web-server-from-spambots

    我们的想法是将禁令存储在PHP(或其他)的数据库中,但不要使用PHP进行任何过滤。每个请求额外的DB命中可能是从快速到低速的转折点。

    执行阻塞的位是内核级防火墙iptables。这由另一个只从数据库中读取的脚本更新。如果你愿意的话,你可以做一些像CSV一样简单的事情,并完全跳过数据库联系。

    无论如何,IPTables 比全面数据库查询更有效。

  2. 如果使用SQL,请确保转义IP输入。我可能是偏执狂,但我已经看到$_SERVER['REMOTE_ADDR']的各种废话。

  3. 的字符串。它们不是数字,而是四个数字的排列。 IPv6是十六进制的。字符串覆盖所有基础,处理成本很低。

  4. 您还应该知道服务器变量可能存在。阅读:Getting The Real IP Of Your Users