какой наиболее эффективный метод защиты от 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> и когда пользователь зайта заходит на страницу - от его имени отправляется запрос на сайт, и дает возможность выполнять практически любые действия знаю что есть такие методы защиты: -проверка реффера -генерация униакльного значения и подстановка его во все формы(злоумышленник не знает его заранее и поэтому обломается). какой из методов наиболее эффективный?
security token, естественно. но с уникальной привязкой под юзера (а то бывают генерят токены которые юзаются от любого юзера в течении 10 минут, допустим) + не плохо бы проверить реферрер.
делаю и то и другое+ еще 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; } }
и проверку сессии на каждой странице: 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; }
а зачем ты проверяешь ип? csrf атака производится от "лица" юзера. от того, что запрос в ифрейме/картинке сессия не перехватится. и проверка бесполезна, если у тебя, конечно, нет xss на каждом углу, что бы у юзера могли перехватить куки. так что, имхо, лишняя нагрузка в базу и вебсерверу.
ip это уже не для csrf)) это если вдруг у юзера угонят phpsessid с его компа(хсс вроде везде проверяю htmlspecialchars)
тогда сделай эту функцию опциональной, что бы в настройках была галка "Привязать сессию к ip". А то тебя проклянут владельцы всяких 3г модемов и динамических ипов. + если угонщик будет в локалке(что распространено) юзера, то ему на проверку пофег.
PHP: if( $_SERVER['REQUEST_METHOD'] == 'POST' && !preg_match('!^http(s)?://' . preg_quote($_SERVER['HTTP_HOST']) . '!i', $_SERVER['HTTP_REFERER'])) exit;
Иии? А токен-то где? Токен должен генериться каждый раз для каждой формы. Проверка реферера вполне вероятно может пойти лесом если на сайте есть пассивка.
а где я его еще должен был сделать? это же класс: 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); } } ?>
разве что сделать в каждой функции разрыв соединения: mysql_close и то после отработки срипта все соединения с бд разрываются
Если на сайте есть пассивка, то никакие токены не защитят от CSRF. Наоборот, это самая распространенная уязвимость.
да и еще: является ли addslashes и приведение к int 100% защитой от скуль-инъекций? просто видел в какомто крэкми скрипт с аддслэшес и интвал на самом сложном уровне gj скульинжектион
addslashes() можно обойти, в зависимости от кодировки. intval() обойти нельзя. Используй mysql_real_escape_string() Так никто и не прошел это задание до сих пор. =) Может быть там уязвимости функций в конкретной версии PHP.
Ужас это а не класс. В каждой функции include "dbconf.php"; Нагуглите готовое решение, можете не использовать, чисто ради того чтоб увидеть как делают это программисты.
переписал класс 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); } } ?>