@Barlow: Nope, the attacker could still send a big ammount of POST requests and one of them may work. What we need to do is slow down his session until he succeeds.
<?php
session_start();
if(isset($_SESSION['failed']))
sleep(2);
public function handle_login() {
if($uid = user::check_password($_REQUEST['email'], $_REQUEST['password'])) {
session_destroy();
return self::authenticate_user($uid);
}
else {
$_SESSION['failed'] = 1;
return self::login_failed();
}
}
?>
sleep
(PHP 4, PHP 5)
sleep — Arrête l'exécution durant quelques secondes
Description
Arrête l'exécution du programme pendant seconds secondes.
Liste de paramètres
- seconds
-
Le retard, en nombre de secondes.
Valeurs de retour
Retourne zéro en cas de succès, FALSE si une erreur survient.
Si l'appel est interrompu par un signal, la fonction sleep() retournera une valeur différente de zéro. Sous Windows, la valeur sera toujours de 192 (la valeur de la constante WAIT_IO_COMPLETION de l'API Windows). Sous les autres plateformes, la valeur retournée sera le nombre de secondes restantes à la fonction sleep().
Erreurs / Exceptions
Si le nombre seconds spécifié est négatif, cette fonction génère une alerte de niveau E_WARNING.
Historique
| Version | Description |
|---|---|
| 5.3.4 | Avant PHP 5.3.4, sous Windows, sleep() retournait toujours NULL lorsque la fonction se terminait, que ce soit de façon normal ou bien par un signal. |
Exemples
Exemple #1 Exemple avec sleep()
<?php
// Heure actuelle
echo date('h:i:s') . "\n";
// Stoppe pour 10 secondes
sleep(10);
// retour !
echo date('h:i:s') . "\n";
?>
Cet exemple affichera (après 10 secondes) :
05:31:23 05:31:33
Voir aussi
- usleep() - Arrête l'exécution durant quelques microsecondes
- time_nanosleep() - Attendre pendant un nombre de secondes et de nanosecondes
- time_sleep_until() - Arrête le script pendant une durée spécifiée
- set_time_limit() - Fixe le temps maximum d'exécution d'un script
You should put sleep into both the pass and fail branches, since an attacker can check whether the response is slow and use that as an indicator - cutting down the delay time. But a delay in both branches eliminates this possibility.
A really simple, but effective way of majorly slowing down bruit force attacks on wrong password attempts.
In my example below, if the end-user gets the password correct, they get to log in at full speed, as expected. For every incorrect password attempt, the users response is delayed by 2 seconds each time; mitigating the chances of a full bruit force attack by a limit of 30 lookups a minute.
I hope this very simple approach will help make your web applications that little bit more secure.
Ashley
<?php
public function handle_login() {
if($uid = user::check_password($_REQUEST['email'], $_REQUEST['password'])) {
return self::authenticate_user($uid);
}
else {
// delay failed output by 2 seconds
// to prevent bruit force attacks
sleep(2);
return self::login_failed();
}
}
?>
Since sleep() can be interrupted by signals i've made a function which can also be interrupted, but will continue sleeping after the signal arrived (and possibly was handled by callback). It's very useful when you write daemons and need sleep() function to work as long as you 'ordered', but have an ability to accept signals during sleeping.
<?php
function my_sleep($seconds)
{
$start = microtime(true);
for ($i = 1; $i <= $seconds; $i ++) {
@time_sleep_until($start + $i);
}
}
?>
Simple function to report the microtime since last called or the microtime since first called.
<?php
function stopWatch($total = false,$reset = true){
global $first_called;
global $last_called;
$now_time = microtime(true);
if ($last_called === null) {
$last_called = $now_time;
$first_called = $now_time;
}
if ($total) {
$time_diff = $now_time - $first_called;
} else {
$time_diff = $now_time - $last_called;
}
if ($reset)
$last_called = $now_time;
return $time_diff;
}
?>
$reset - if true, resets the last_called value to now
$total - if true, returns the time since first called otherwise returns the time since last called
Notice that sleep() delays execution for the current session, not just the script. Consider the following sample, where two computers invoke the same script from a browser, which doesn't do anything but sleep.
PC 1 [started 14:00:00]: script.php?sleep=10 // Will stop after 10 secs
PC 1 [started 14:00:03]: script.php?sleep=0 // Will stop after 7 secs
PC 2 [started 14:00:05]: script.php?sleep=0 // Will stop immediately
http://php.net/session_write_close may be used to address this problem.
I hope this code will help somebody to solve the problem of not being able to flush or output the buffer to the browser (I use IE7).
It may work for you with just [ echo str_repeat(".", 4096); ] and without even using ob_... and flush.
<?php
ob_start();
ob_implicit_flush(true);
//[ OR ] echo "..."; ob_flush(); flush();
set_time_limit(0);
function sleep_echo($secs) {
$secs = (int) $secs;
$buffer = str_repeat(".", 4096);
//echo $buffer."\r\n<br />\r\n";
for ($i=0; $i<$secs; $i++) {
echo date("H:i:s", time())." (".($i+1).")"."\r\n<br />\r\n".$buffer."\r\n<br />\r\n";
ob_flush();
flush();
sleep(1);
//usleep(1000000);
}
}
sleep_echo(30);
ob_end_flush();
?>
Remember that sleep() means "Let PHP time to do some other stuff".
That means that sleep() can be interrupted by signals. That is important if you work with pcntl_signal() and friends.
This will allow you to use negative values or valuer below 1 second.
<?php slaap(0.5); ?>
<?php
function slaap($seconds)
{
$seconds = abs($seconds);
if ($seconds < 1):
usleep($seconds*1000000);
else:
sleep($seconds);
endif;
}
?>
This is a critical thing to use time delay function as sleep() Because a beginner can find that this is not working and he/she will see that all output appearing at a time.
A good way to implement this is by using the function - ob_implicit_flush() then you don't need to use flush() function explicitly.
A sample code :
<?php
ob_implicit_flush(true);
for($i=0;$i<5;$i++)
{
$dis=<<<DIS
<div style="width:200px; background-color:lime;border:1px; text-align:center;text-decoration:blink;">
$i
</div>
DIS;
echo $dis;
sleep(5);
//flush();
}
Very useful to prevent password brute forcing! Simply add few seconds timeout to login script and the probability to guess the password decreases a lot!
This may seem obvious, but I thought I would save someone from something that just confused me: you cannot use sleep() to sleep for fractions of a second. This:
<?php sleep(0.25) ?>
will not work as expected. The 0.25 is cast to an integer, so this is equivalent to sleep(0). To sleep for a quarter of a second, use:
<?php usleep(250000) ?>
Note: The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), the sleep() function, database queries, etc. is not included when determining the maximum time that the script has been running.
it is a bad idea to use sleep() for delayed output effects as
1) you have to flush() output before you sleep
2) depending on your setup flush() will not work all the way to the browser as the web server might apply buffering of its own or the browser might not render output it thinks not to be complete
netscape for example will only display complete lines and will not show table parts until the </table> tag arrived
so use sleep if you have to wait for events and don't want to burn to much cycles, but don't use it for silly delayed output effects!
