简体   繁体   中英

Prevent attack on login using sessions in php

i'm trying to use sessions to store the amount of login attempts. When the maximum of login attempts is reached i'm storing the client's ip address in a blacklist table.

Some things i've taken into account, you might need to know about:

  • I'm using session_regenerate_id(); after i set a session value.
  • I'm not using any cookies apart from the session since this is not necessary and not 2012 :p
  • The users ip is blacklisted until i mannually delete his row from the blacklist table.
  • The SESSION_MAX_ATTEMPTS is a defined constant and set to 5.
  • The index.php?module=login&task=blacklist page is just showing the user a message that it's blacklisted. This page does not have any functionallity.
  • i'm using a custom build php framework, so i had to translate some OOP called method's to simplified php code.

The following function is called before a login query is executed:

private function preventAttack()
{
    $blocked = getData("SELECT count(*) as blocked FROM blacklist WHERE ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
    if($blocked[0]["blocked"] == "1")
    {
        redirect("index.php?module=login&task=blacklist");
    }
    $old = (int)$this->session->get("login_attempts");
    if(!empty($old))
    {           
        if($old > SESSION_MAX_ATTEMPTS)
        {
            setData("INSERT INTO blacklist SET ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
            redirect("index.php?module=login&task=blacklist");
        }
        else
        {
            $old++;
            $this->session->set("login_attempts",$old);
        }
    }
    else
    {
        $this->session->set("login_attempts", 0);
    }
}

The first if statement works including both query's but i'm stuck at what's the best way to store the amount of attempts and what's the best way to ++ it? Maybe you guys can set me in the right direction.

If you have any questions about my code, please add a comment. I know it's a bit unreadable since it's from my framework, i've translated this a bit before posting it.

Store the number of failed attempts in the database, not the session. NB: You probably need to keep each failure along with a timestamp in its own record (and ignore/delete anything older than a threshold).

By the way, in response to deceze's comment:

Ginormous flaw in this approach: sessions depends on the client sending a cookie. Real attackers will simply not send the cookie back. ziiiing You'll have to go by IP for everything.

The solution to this is that you don't accept login attempts that don't come with a valid session cookie, set elsewhere.

Thanks a lot guys, i've learned a lot from your comments. For users with the same problem i'll explain what i've learned and how i'm using that knowledge.

What i've learned so far:

  1. Real attackers will simply not send a cookie back. So using cookies or sessions doesn't make any sense in this case.
  2. If you want to blacklist attackers, use can use a firewall that does this automatically for you. It makes no sense to do this from your script, sessions are too easily circumvented and if you check IP addresses you could block out entire offices or schools on the same external IP.
  3. Whatever you do: store the login attempts data only on the server in a database/flatfile/etc. The user or attacker will not be able to edit this data so easily.
  4. And if you do store data on your web server for performance, store it in a file, not a DB.

If i forgot something please comment and i will edit this post.

I checked with my hosting provider and they are already blocking out a lot of these attackers using solutions like the firewall mentioned above. So i will stop trying to also do this in my scripts.

My script is fixed now and only blacklisting users and noob hackers guessing passwords:

private function preventAttack()
{
    $blocked = getData("SELECT count(*) as blocked FROM blacklist WHERE ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
    if($blocked[0]["blocked"] == "1")
    {
        redirect("index.php?module=login&task=blacklist");
    }
    $old = (int)$this->session->get("login_attempts");
    if($old > 0)
    {           
        if(($old + 1) >= SESSION_MAX_ATTEMPTS)
        {
            setData("INSERT INTO blacklist SET ip = @Value0;", Array( $_SERVER['REMOTE_ADDR'] ));
            $this->session->set("login_attempts", 0);
            redirect("index.php?module=login&task=blacklist");
        }
        else
        {
            $old++;
            $this->session->set("login_attempts",$old);
        }
    }
    else
    {
        $this->session->set("login_attempts", 1);
    }
}

Since i'm not quite sure how many users this platform is going to get and i don't want a possible high mysql server load i've decided not to store the login attempts in the database. Maybe in the future, who knows.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM