защита от CSRF

Discussion in 'PHP' started by realcoder, 18 Jan 2012.

  1. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    какой наиболее эффективный метод защиты от csrf-атак?
    атака малораспространенная, если кто не знает: когда делают невидимый iframe:
    HTML:
    <iframe src="ololo.htm" width=0 height=0 />
    запихивают код типа:
    PHP:
    <form action="http://ololo.com/target.php"><!-- сайткоторый атакуется->
    ....
    </
    form>
    <
    script>
    document[0].forms[0].submit();
    </script>
    и когда пользователь зайта заходит на страницу - от его имени отправляется запрос на сайт, и дает возможность выполнять практически любые действия
    знаю что есть такие методы защиты:
    -проверка реффера
    -генерация униакльного значения и подстановка его во все формы(злоумышленник не знает его заранее и поэтому обломается).
    какой из методов наиболее эффективный?
     
    #1 realcoder, 18 Jan 2012
    Last edited: 18 Jan 2012
  2. justonline

    justonline network ninja

    Joined:
    27 Jul 2011
    Messages:
    499
    Likes Received:
    60
    Reputations:
    53
    security token, естественно. но с уникальной привязкой под юзера (а то бывают генерят токены которые юзаются от любого юзера в течении 10 минут, допустим) + не плохо бы проверить реферрер.
     
  3. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    делаю и то и другое+ еще ip:
    PHP:
     function login($login,$pass)
      {
        include 
    "dbconf.php";  //коннект к мусклу: mysql_connect(....); mysql_select_db(....);
        
    $login=addslashes($login);
        
    $pass=md5($pass);
        
    $sql="select count(*),id from `users` where `login`='$login' and `password`='$pass'";
        
    $result=mysql_query($sql);
        
    $count=mysql_result($result,0,0);
        
    $userid=mysql_result($result,0,1);
        if(
    $count>0)
        {
           
    $_SESSION['uid']=$userid;
           
    $this->uid=$_SESSION['uid'];//инит свойства uid uid
           
    mysql_query("delete from `online` where `userid`=".$userid);//kill'нем все предыдущие сессии
           
    $sql="insert into `online` (`id`,`userid`,`time`,`ip`,`sess_key`) values (null,".$userid.",'".date('Y-m-d H:i:s')."','".$_SERVER['REMOTE_ADDR']."','".md5(rand(0,255).rand(0,255).rand(0,255).$_SERVER['REMOTE_ADDR'].time())."')";
           
    mysql_query($sql);
           return 
    true;
        }
        else
        {
        return 
    false;
        }
      }
     
  4. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    и проверку сессии на каждой странице:
    PHP:
     function check_secure()//проверка ip
     
    {
      include 
    "dbconf.php";
      
    $sql="select ip from `online` where `userid`= ".intval($this->uid).;
      
    $result=mysql_result(mysql_query($sql),0,0);
      if(
    $result==$_SERVER['REMOTE_ADDR'])
      {
        return 
    true;
      }
      return 
    false;
     }
     
  5. justonline

    justonline network ninja

    Joined:
    27 Jul 2011
    Messages:
    499
    Likes Received:
    60
    Reputations:
    53
    а зачем ты проверяешь ип? csrf атака производится от "лица" юзера. от того, что запрос в ифрейме/картинке сессия не перехватится. и проверка бесполезна, если у тебя, конечно, нет xss на каждом углу, что бы у юзера могли перехватить куки.
    так что, имхо, лишняя нагрузка в базу и вебсерверу.
     
  6. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    ip это уже не для csrf))
    это если вдруг у юзера угонят phpsessid с его компа(хсс вроде везде проверяю htmlspecialchars)
     
  7. justonline

    justonline network ninja

    Joined:
    27 Jul 2011
    Messages:
    499
    Likes Received:
    60
    Reputations:
    53
    тогда сделай эту функцию опциональной, что бы в настройках была галка "Привязать сессию к ip". А то тебя проклянут владельцы всяких 3г модемов и динамических ипов.
    + если угонщик будет в локалке(что распространено) юзера, то ему на проверку пофег.
     
  8. LStr1ke

    LStr1ke Elder - Старейшина

    Joined:
    29 Jul 2009
    Messages:
    801
    Likes Received:
    145
    Reputations:
    73
    Проверять реферер.
     
  9. Boolean

    Boolean Elder - Старейшина

    Joined:
    5 Sep 2010
    Messages:
    147
    Likes Received:
    83
    Reputations:
    78
    PHP:
    if( $_SERVER['REQUEST_METHOD'] == 'POST' && !preg_match('!^http(s)?://' preg_quote($_SERVER['HTTP_HOST']) . '!i'$_SERVER['HTTP_REFERER']))
            exit;  
     
  10. [stranger]

    [stranger] Member

    Joined:
    2 Feb 2010
    Messages:
    167
    Likes Received:
    29
    Reputations:
    4
    Иии? А токен-то где? Токен должен генериться каждый раз для каждой формы.
    Проверка реферера вполне вероятно может пойти лесом если на сайте есть пассивка.
     
  11. b3

    b3 Banned

    Joined:
    5 Dec 2004
    Messages:
    2,170
    Likes Received:
    1,155
    Reputations:
    202
    гыгы) инлкуд внутри функции)
     
    1 person likes this.
  12. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    а где я его еще должен был сделать?
    это же класс:
    PHP:
    <?php
    /*
    (c) CodeMaster 2012
    */
    class sess{    //класс сессии

     
    var $uid;

     function 
    check_secure()//проверка ip адреса
     
    {
      include 
    "dbconf.php";
      
    $sql="select ip from `online` where `userid`= ".intval($this->uid);
      
    $result=mysql_result(mysql_query($sql),0,0);
      if(
    $result==$_SERVER['REMOTE_ADDR'])
      {
        return 
    true;
      }
      return 
    false;
     }

     function 
    upd_sess()//обновляет время последеней активности
     
    {
      include 
    "dbconf.php";
      
    mysql_query("update `online` set `time`='".date('Y-m-d H:i:s')."'");
     }

     function 
    sess()  //конструктор
     
    {
      
    session_start();//инициализация сессии
      
    if(isset($_SESSION['uid']))
      
    $this->uid=$_SESSION['uid'];//инициализация свойства uid
      
    else $this->uid=0;
     }

     function 
    login($login,$pass)
      {
        include 
    "dbconf.php";  //подключение к бд: mysql_connect(....); mysql_select_db(....);
        
    $login=addslashes($login);
        
    $pass=md5($pass);
        
    $sql="select count(*),id from `users` where `login`='$login' and `password`='$pass'";
        
    $result=mysql_query($sql);
        
    $count=mysql_result($result,0,0);
        
    $userid=mysql_result($result,0,1);
        if(
    $count>0)
        {
           
    $_SESSION['uid']=$userid;
           
    $this->uid=$_SESSION['uid'];//инициализация свойства uid
           
    mysql_query("delete from `online` where `userid`=".$userid);//kill'нем все предыдущие сессии
           
    $sql="insert into `online` (`id`,`userid`,`time`,`ip`,`sess_key`) values (null,".$userid.",'".date('Y-m-d H:i:s')."','".$_SERVER['REMOTE_ADDR']."','".md5(rand(0,255).rand(0,255).rand(0,255).$_SERVER['REMOTE_ADDR'].time())."')";
           
    mysql_query($sql);
           return 
    true;
        }
        else
        {
        return 
    false;
        }
      }




     function 
    current_user()     //логин текущего пользователя
     
    {
      if(
    $uid>0)
      {
        include 
    "dbconf.php";
        
    $sql="select * from `users` where `id`=".$this->uid;
        
    $result=mysql_query($sql);
        
    $ft=mysql_fetch_array($result);
        return 
    $ft['login'];
      }
      else return 
    false;
     }

     function 
    check_token($sec_token)
     {
      include 
    "dbconf.php";
      
    $sql="select count(*) from `online` where `uid`=".intval($this->uid)." and `sess_key`='".addslashes($sec_token)."'";
      return 
    mysql_result(mysql_query($sql),0,0)==1;
     }

     function 
    logout()   //выход
     
    {
      include 
    "dbconf.php";
      
    mysql_query("delete from `online` where `userid`=".intval($this->uid));
      
    $_SESSION=array();
      
    session_destroy();
      
    $uid=0;
     }

     function 
    autorized()//пользователь авторизован
     
    {
     return (
    $uid>0);
     }

    }




    ?>
     
  13. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    разве что сделать в каждой функции разрыв соединения: mysql_close
    и то после отработки срипта все соединения с бд разрываются
     
  14. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Если на сайте есть пассивка, то никакие токены не защитят от CSRF.

    Наоборот, это самая распространенная уязвимость.
     
    #14 M_script, 19 Jan 2012
    Last edited: 19 Jan 2012
  15. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    да и еще:
    является ли addslashes и приведение к int 100% защитой от скуль-инъекций?
    просто видел в какомто крэкми скрипт с аддслэшес и интвал на самом сложном уровне gj скульинжектион
     
  16. phpdreamer

    phpdreamer Member

    Joined:
    26 Jul 2009
    Messages:
    522
    Likes Received:
    86
    Reputations:
    19
    Внимательно читай описание
    http://php.net/manual/ru/function.addslashes.php
     
  17. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    addslashes() можно обойти, в зависимости от кодировки. intval() обойти нельзя.
    Используй mysql_real_escape_string()
    Так никто и не прошел это задание до сих пор. =)
    Может быть там уязвимости функций в конкретной версии PHP.
     
  18. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    ясно. лучше использовать mysql_real_excape_string...
     
  19. b3

    b3 Banned

    Joined:
    5 Dec 2004
    Messages:
    2,170
    Likes Received:
    1,155
    Reputations:
    202
    Ужас это а не класс. В каждой функции include "dbconf.php"; Нагуглите готовое решение, можете не использовать, чисто ради того чтоб увидеть как делают это программисты.
     
    1 person likes this.
  20. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    переписал класс :D
    PHP:
    <?php
    /*
    (c) CodeMaster 2012
    */

    class sess{    //êëàññ ñåññèè

     
    var $uid;
     var 
    $mysql;

     function 
    check_secure()//ïðîâåðêà ip àäðåñà
     
    {
      
    $sql="select ip from `online` where `userid`= ".intval($this->uid);
      
    $row=$this->mysql->query($sql)->fetch_array();
      if(
    $row[0]==$_SERVER['REMOTE_ADDR'])
      {
        return 
    true;
      }
      return 
    false;
     }

     function 
    upd_sess()//îáíîâëÿåò âðåìÿ ïîñëåäåíåé àêòèâíîñòè
     
    {
      
    $this->mysql->query("update `online` set `time`='".date('Y-m-d H:i:s')."'");
     }

     function 
    sess($mysql)  //êîíñòðóêòîð
     
    {
      
    session_start();//èíèöèàëèçàöèÿ ñåññèè
      
    if(isset($_SESSION['uid']))
      
    $this->uid=$_SESSION['uid'];//èíèöèàëèçàöèÿ ñâîéñòâà uid
      
    else $this->uid=0;
      
    $this->mysql$mysql;
     }

     function 
    token()
     {
     return 
    md5(rand(0,255).rand(0,255).rand(0,255).$_SERVER['REMOTE_ADDR'].time());
     }

     function 
    ceate_new_token()
     {
     
    $token=$this->token();
     
    $this->mysql->query("insert into `tokens`(`id`,`token`,`uid`) values(null,'".$this->mysql->real_escape_string($this->token())."',".intval($this->uid).")");
     return 
    $this->mysql->query("select * from `tokens` where `token`='".$this->mysql->real_escape_string($token)."' and `uid`=".intval($this->uid))->fetch_array();

     }

     function 
    login($login,$pass)
      {
        
    $login=$this->mysql->real_escape_string($login);
        
    $pass=md5($pass);
        
    $sql="select count(*),id from `users` where `login`='$login' and `password`='$pass'";
        
    $result=$this->mysql->query($sql)->fetch_array();
        
    $count=$result[0];
        
    $userid=$result[1];
        if(
    $count>0)
        {
           
    $_SESSION['uid']=$userid;
           
    $this->uid=$_SESSION['uid'];//èíèöèàëèçàöèÿ ñâîéñòâà uid
           
    $this->mysql->query("delete from `online` where `userid`=".$userid);//kill'íåì âñå ïðåäûäóùèå ñåññèè
           
    $sql="insert into `online` (`id`,`userid`,`time`,`ip`) values (null,".$userid.",'".date('Y-m-d H:i:s')."','".$_SERVER['REMOTE_ADDR']."')";
           
    $this->mysql->query($sql);
           return 
    true;
        }
        else
        {
        return 
    false;
        }
      }




     function 
    current_user()     //ëîãèí òåêóùåãî ïîëüçîâàòåëÿ
     
    {
      if(
    $uid>0)
      {
        
    $sql="select * from `users` where `id`=".$this->uid;
        
    $result=$this->mysql->query($sql)->fetch_array();
        return 
    $result['login'];
      }
      else return 
    false;
     }

     function 
    check_token($token,$id)
     {
      
    $sql="select count(*) from `tokens` where `id`=".intval($id)." and `token`='".$this->mysql->real_escape_string($token)."' and `uid`=".intval($this->uid);
      
    $row=$this->mysql->query($sql)->fetch_array();
      return 
    $row[0]==1;
     }

     function 
    logout()   //âûõîä
     
    {
      
    $this->mysql->query("delete from `online` where `userid`=".intval($this->uid));
      
    $this->mysql->query("delete from `tokens` where `uid`=".intval($this->uid));
      
    $_SESSION=array();
      
    session_destroy();
      unset(
    $this->uid);
     }
     function 
    __destruct()
     {
     unset(
    $this->uid);
     unset(
    $this->mysql);
     }

     function 
    autorized()//ïîëüçîâàòåëü àâòîðèçîâàí
     
    {
     return (
    $this->uid>0);
     }

    }




    ?>
     
    #20 realcoder, 19 Jan 2012
    Last edited: 19 Jan 2012
Loading...
Similar Threads - защита CSRF
  1. GAiN
    Replies:
    3
    Views:
    8,270