延迟执行 PHP 脚本
阻止机器人、恶意用户等过快执行 php 脚本的最佳方法是什么? 如果我使用 usleep()
或 sleep()
函数暂时“什么也不做”(就在所需的代码执行之前),可以吗?简直愚蠢,有更好的方法吗?
示例:
function login() {
//enter login code here
}
function logout() {
//enter logout code here
}
如果我只是在登录和注销代码之前添加 usleep(3000000)
,可以吗?或者是否有更好、更明智的方法来实现我想要实现的目标?
编辑:根据下面的建议,usleep
或sleep
是否只会导致处理器脱离当前用户正在执行的当前脚本,或者是否会导致它脱离整个服务? 即,如果一个用户+脚本调用sleep
/usleep
,那么所有并发的用户+脚本也会被延迟吗?
What is the best way to stop bots, malicious users, etc. from executing php scripts too fast? Is it ok if I use the usleep()
or sleep()
functions to simply do "nothing" for a while (just before the desired code executes), or is that plain stupid and there are better ways for this?
Example:
function login() {
//enter login code here
}
function logout() {
//enter logout code here
}
If I just put, say, usleep(3000000)
before the login and logout codes, is that ok, or are there better, wiser ways of achieving what I want to achieve?
edit: Based on the suggestions below, does then usleep
or sleep
only cause the processor to disengage from the current script being executed by the current user, or does it cause it to disengage from the entire service? i.e. If one user+script invokes a sleep
/usleep
, will all concurrent users+scripts be delayed too?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
大多数 Web 服务器(例如 Apache)的工作方式是维护工作线程的集合。 当执行 PHP 脚本时,一个线程运行 PHP 脚本。
当您的脚本执行
sleep(100)
时,脚本需要 100 秒才能执行。这意味着您的工作线程被占用 100 秒。问题是,您的工作线程数量非常有限 - 假设您有 10 个线程,并且有 10 个人登录 - 现在您的 Web 服务器无法提供任何进一步的响应。
限制登录速率(或其他操作)的最佳方法)是使用某种快速内存存储(memcached 非常适合此操作),但是这需要运行单独的进程并且非常复杂(如果你运行像 Facebook 这样的东西,你可能会这样做......)。
更简单的是,您可以有一个数据库表来存储
user_id
或ip_address
、first_failed
和failure_counter
。每次登录失败时,您(用伪代码)都会这样做:
也许不是最有效的,并且有更好的方法,但它应该很好地阻止暴力破解。 使用memcached基本是一样的,只不过数据库换成了memcached(速度更快)
The way most web servers work (Apache for example) is to maintain a collection of worker threads. When a PHP script is executed, one thread runs the PHP script.
When your script does
sleep(100)
, the script takes 100 seconds to execute.. That means your worker thread is tied up for 100 seconds.The problem is, you have a very finite number of worker-threads - say you have 10 threads, and 10 people login - now your web-server cannot serve any further responses..
The best way to rate-limit logins (or other actions) is to use some kind of fast in-memory storage thing (memcached is perfect for this), but that requires running separate process and is pretty complicated (you might do this if you run something like Facebook..).
Simpler, you could have a database table that stores
user_id
orip_address
,first_failed
andfailure_counter
.Every time you get a failed login, you (in pseudo code) would do:
Maybe not the most efficient, and there is better ways, but it should stop brute-forcing pretty well. Using memcached is basically the same, but the database is replaced with memcached (which is quicker)
我首先要问你真正想阻止什么? 如果是拒绝服务攻击,那么我不得不说,如果您受到可以添加到 PHP 脚本中的内容的限制,您将无能为力。 最先进的技术远远超出了我们程序员所能防范的范围。 开始研究为此目的设计的系统管理工具。
或者您是否试图限制您的服务,以便真人可以访问但机器人不能? 如果是这样,我会研究一些“验证码”技术。
或者您是否试图阻止用户每秒轮询您的网站以寻找新内容? 如果是这样,我会研究提供 RSS 提要或其他通知他们的方式,这样他们就不会耗尽您的带宽。
或者是别的什么?
一般来说,我认为 sleep() 和 usleep() 都不是一个好方法。
I would first ask what you are really trying to prevent? If it is denial-of-service attacks, then I'd have to say there is nothing you can do if you are limited by what you can add to PHP scripts. The state of the art is so much beyond what we as programmers can protect against. Start looking at sysadmin tools designed for this purpose.
Or are you trying to limit your service so that real people can access it but bots cannot? If so, I'd look at some "captcha" techniques.
Or are you trying to prevent users from polling your site every second looking for new content? If so, I'd investigate providing an RSS feed or some other way of notifying them so they don't eat up your bandwidth.
Or is it something else?
In general, I'd say neither sleep() nor usleep() is a good way.
您建议的方法将迫使所有用户在登录前进行不必要的等待。
大多数 LAMP 服务器(实际上是大多数路由器/交换机)已配置为防止拒绝服务攻击。 他们通过拒绝来自同一 IP 地址的多个连续请求来实现此目的。
Your suggested method will force ALL users to wait unnecessarily before logging in.
Most LAMP servers (and most routers/switches, actually) are already configured to prevent Denial of Service attacks. They do this by denying multiple consecutive requests from the same IP address.
你不想让你的 php.ini 休眠。 这样做将大大减少您的服务器可以处理的并发请求的数量,因为您将保持连接处于打开状态等待。
大多数 HTTP 服务器都具有可以避免 DoS 攻击的功能,但如果做不到这一点,您应该只跟踪最近多次看到的 IP 地址,然后向它们发送 403 Forbidden 并显示一条消息,要求它们稍等一下。
如果由于某种原因,您不能指望 REMOTE_ADDR 是用户特定的(每个人都在同一防火墙后面等),您可以在登录表单中证明一个挑战,并使远程浏览器对其进行扩展计算(例如,因式分解一个数字) ),您可以在服务器端快速检查(通过快速乘法)。
You don't want to put a sleep in your php. Doing so will greatly reduce the number of concurrent requests your serve can handle since you'll have connections held open waiting.
Most HTTP servers have features you can enable to avoid DoS attacks, but failing that you should just track IP addresses you've seen too many times too recently and send them a 403 Forbidden with a message asking them to wait a second.
If for some reason you can't count on REMOTE_ADDR being user specific (everyone behind the same firewall, etc.) you could prove a challenge in the login form and make the remote browser do an extended calculation on it (say, factor a number) that you can quickly check on the server side (with speedy multiplication).