【问题标题】:I don't understand PHP sleep() behavior我不明白 PHP sleep() 行为
【发布时间】:2013-05-31 18:54:24
【问题描述】:

我有这个表格:

<form method="post" action="secret.php">
    <label for="pw">Password: </label><input type="password" name="pw" id="pw" />
</form>

这是secret.php:

<?php 
if(isset($_POST["pw"])) {
    if($_POST["pw"] == "hello") {
        echo("<strong>Good pw.</strong><br />");
    } else {
        echo("<strong>Bad pw.</strong><br />");
        echo("<a href=\"form.php\">Back</a>");
        sleep(5);
    }
} else {
    header("Location: /tut/first/form.php");
}
?>

如果密码错误,它会在显示 Bad pw 之前休眠。当我提交表单时,它在表单页面上休眠 5 秒,然后更改页面并显示 Bad pw。为什么?

【问题讨论】:

  • sleep() 只是将当前线程的执行延迟到您告诉它的时间。在当前请求完成之前,不会将输出发送到浏览器。我猜你可以使用输出缓冲...
  • 你为什么要睡觉?上面的代码可能是解决问题的有效方法,也许只是不能解决您的问题,那么您打算通过 sleep 解决什么问题?

标签: php sleep


【解决方案1】:

发生的情况是您导致 PHP 脚本进入休眠状态。脚本必须先完成,然后才能将结果发送回客户端(浏览器)。*因此,您会导致脚本在响应客户端密码错误之前多花 5 秒时间。

由于您不想在这里避免暴力情况,因此我建议您这样做:

<?php 
if(isset($_POST["pw"])) {
    if($_POST["pw"] == "hello") {
        echo("<strong>Good pw.</strong><br />");
    } else {
        echo("<strong>Bad pw.</strong><br />");
        echo("<script type=\"text/javascript\">");
            echo ("setTimeout(function() {");
                echo ("window.location = form.php;"); //might need a more complete URL here
            echo ("}, 5)"); //sleep for 5 seconds before redirecting
        echo("</script>");
        sleep(5);
    }
} else {
    header("Location: /tut/first/form.php");
}
?>

*输出实际上是在 PHP 脚本中编写的,但是通过缓冲,除了标题和非常大的页面之外,您看不到这有太大的不同。

【讨论】:

  • 哦,我明白了。那么我应该怎么做呢?用javascript做吗?
  • Javascript 相当不安全,因为客户端可以更改它,或者他们可以制作自己的程序来访问您的 php 文件而没有任何限制。我在编辑中提出了一个建议,应该会有所帮助。
  • @BlargleMonster 这样吗?他唯一想做的就是从“错误密码”页面重定向到原始表单。 javascript 可以很好地解决这个问题(除非用户禁用了它,这取决于你是否关心它)。如果用户想搞砸 js,那是他们的错——他们只会继续看到“密码错误”页面。这里没有安全问题。
  • 我要做的是回显错误密码,然后休眠 5 秒,然后重定向到表单页面。 JS 会工作,但如果可能的话,我想用 PHP 做,我试图理解你的回答 Blargle。
  • @Maxwell 在这种情况下,javascript 就可以了。您可能想要回显&lt;strong&gt;Bad pw.&lt;/strong&gt;&lt;br /&gt;,然后回显一个小的javascript &lt;script&gt; 块,它将休眠并重定向它们。它应该根据它在响应页面中的位置自动加载和执行。
【解决方案2】:

您需要研究输出缓冲,尽管在我看来,逻辑是有缺陷的。

This 可能会有所帮助

【讨论】:

    【解决方案3】:

    如果您想立即向浏览器回显某些内容,请尝试在要将输出缓冲区刷新到浏览器时执行flush()。此外,您可能需要禁用可能会干扰输出缓冲的压缩(如 gzip)。

    但是,话虽如此,但您的想法完全错误。用户只需打开另一个选项卡/刷新,服务器将再次验证登录信息,因此sleep() 不会产生您认为的效果。

    我实际上设计了类似的东西,这就是我所做的:

    创建一个名为 failed_logins 的数据库表和另一个名为 login_bans 的数据库表,两者都基于 IP 地址。每次用户提供不正确的信息时,在 failed_logins 表中添加一个条目。您要做的是对其进行分层,以便在第一次登录后,用户被禁止 5 秒,在第二次之后,它会上升到 15 秒,并且在一段时间内(比如 2 小时)用户被禁止 3 秒或更多禁赛45秒。这一切都是在服务器端完成的,因此用户无法采取任何措施来规避禁令。因此,您必须在他们每次访问该页面时检查他们的 IP,以查看他们的 IP 是否已被禁止。

    然后在客户端显示一个倒数计时器,其中包含被禁止的剩余秒数并禁用提交按钮。

    【讨论】:

    • 但是如果用户输入了错误的密码,我希望用户在 5 秒后自动重定向到表单。我还想在他被重定向时回显 Bad pw。
    • 最好只在客户端使用 JS,而不是 PHP,但请确保您也在后端使用类似我这里的东西来执行此操作。使用sleep() 实际上可能是一个 DDoS 漏洞,尤其是 5 秒。想象一下成千上万的人同时连接,每一个人都会产生一个新进程,甚至无法在 5 秒内结束。
    猜你喜欢
    • 2023-03-10
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    • 1970-01-01
    • 2022-10-15
    • 2011-01-14
    相关资源
    最近更新 更多