sauviq
Last Updated: May 21, 2018
·
3.801K
· jasny
Arnold

Brute force protection in PHP

If you have a system where users can subscribe and choose there own passwords, you are probably a target for brute force attacks like a dictionary attack. You can limit this problem by showing user how strong their password is. However forcing users to enter a really strong password will annoy them, since they like something they can remember.

Another way wall you can put up is blocking an IP address for a few minutes upon a number of login failures. This is not a waterproof protection, but the hacker now requires a botnet to perform the brute force attack. This is a hurdle that should keep at the casual hackers and script kiddies out. So based on the data you’re protecting this should be a decent defense.

Setting up this defense isn’t difficult. I’ll show an example how to do this with APC user cache.

<?php
  $apc_key = "{$_SERVER['SERVER_NAME']}~login:{$_SERVER['REMOTE_ADDR']}";
  $tries = (int)apc_fetch($apc_key);
  if ($tries >= 10) {
    header("HTTP/1.1 429 Too Many Requests");
    echo "You've exceeded the number of login attempts. We've blocked IP address {$_SERVER['REMOTE_ADDR']} for a few minutes.";
    exit();
  }

  $success = login($_POST['username'], $_POST['password']);
  if (!$success) {
    apcu_inc($apc_key, $tries+1, 600);  # store tries for 10 minutes
  } else {
    apc_delete($apc_key);
  }

Increasing the block time

Blocking an IP might effect a whole office which can be annoying. Starting with a low timeout and increasing it each time an IP is blocked will help against it.

<?php
  $apc_key = "{$_SERVER['SERVER_NAME']}~login:{$_SERVER['REMOTE_ADDR']}";
  $apc_blocked_key = "{$_SERVER['SERVER_NAME']}~login-blocked:{$_SERVER['REMOTE_ADDR']}";

  $tries = (int)apc_fetch($apc_key);
  if ($tries >= 10) {
    header("HTTP/1.1 429 Too Many Requests");
    echo "You've exceeded the number of login attempts. We've blocked IP address {$_SERVER['REMOTE_ADDR']} for a few minutes.";
    exit();
  }

  $success = login($_POST['username'], $_POST['password']);
  if (!$success) {
    $blocked = (int)apc_fetch($apc_blocked_key);

    apc_store($apc_key, $tries+1, pow(2, $blocked+1)*60);  # store tries for 2^(x+1) minutes: 2, 4, 8, 16, ...
    apc_store($apc_blocked_key, $blocked+1, 86400);  # store number of times blocked for 24 hours
  } else {
    apc_delete($apc_key);
    apc_delete($apc_blocked_key);
  }
Say Thanks
Respond

2 Responses
Add your response

29304

The above example is note working for me.
When i am print the $tries variable , it always showing 0.

7 months ago ·
29849
Hinh xam hoa anh dao dep cho nam va nu 17

Great article, and one that I feel more people should be taught in schools and colleges…
http://abcdeya.com

7 days ago ·