Атака с использованием межсайтовой подделки запроса (CSRF) – это тип уязвимости веб-приложения, когда жертва непреднамеренно запускает скрипт в своем браузере, который использует текущую сессию авторизованного пользователя в определенном сайте. Атаки CSRF могут производиться через GET или POST запросы. Данная статья покажет вам, как защитить свое веб-приложение от атак CSRF.
Метод
Мы будем использовать два метода для защиты от CSRF атак ваших GET и POST запросов.
Первый метод заключается в использовании случайного ключа при каждом запросе, это уникальная строка, генерируемая для каждой сессии. Мы генерируем ключ, а затем включаем его в каждую форму в виде скрытого поля. Далее, система проверяет валидность формы, сравнивая ключ и значение, хранимое в сессионной переменной пользователя. То есть, если злоумышленник захочет сгенерировать запрос, он должен будет знать значение ключа.
Второй метод – это использование случайных названий для каждого поля формы. Значение случайного имени для каждого поля хранится в сессионной переменной и после того, как форма отправлена (произошел сабмит), система генерирует новые случайные названия полей. То есть, если злоумышленник захочет произвести атаку, ему нужно будет знать эти случайные названия полей формы.
К примеру, запрос, который раньше выглядел вот так:
Будет выглядеть вот так:
Шаги
Это основной файл, который будет содержать все методы, необходимые для предотвращения атак CSRF.
-
Создайте файл csrf.class.php. Начните, создав файл, и сохраните его со следующим содержимым:
<?php class csrf {
-
Создайте метод get_token_id().
Эта функция получает id ключа (токен) из сессионной переменной, если же он еще не был создан, то она генерирует случайный токен.
public function get_token_id () { if ( isset ( $_SESSION [ 'token_id' ])) { return $_SESSION [ 'token_id' ]; } else { $token_id = $this -> random ( 10 ); $_SESSION [ 'token_id' ] = $token_id ; return $token_id ; } }
-
Создайте метод get_token().
Эта функция получает значение токена, если же значение еще не было сгенерировано, то оно генерируется.
public function get_token () { if ( isset ( $_SESSION [ 'token_value' ])) { return $_SESSION [ 'token_value' ]; } else { $token = hash ( 'sha256' , $this -> random ( 500 )); $_SESSION [ 'token_value' ] = $token ; return $token ; } }
-
Создайте метод check_valid().
Эта функция проверяет на валидность id и значение токена. Проверка происходит путем сравнения значений, полученных при GET или POST запросах со значениями, хранимыми в сессионной переменной пользователя.
public function check_valid ( $method ) { if ( $method == 'post' || $method == 'get' ) { $post = $_POST ; $get = $_GET ; if ( isset ( ${$method} [ $this -> get_token_id ()]) && ( ${$method} [ $this -> get_token_id ()] == $this -> get_token ())) { return true ; } else { return false ; } } else { return false ; } }
-
Создайте метод form_names().
Это вторая защита против атак CSRF, описанная в этой статье. Эта функция генерирует случайные имена для полей формы.
public function form_names ( $names , $regenerate ) { $values = array (); foreach ( $names as $n ) { if ( $regenerate == true ) { unset ( $_SESSION [ $n ]); } $s = isset ( $_SESSION [ $n ]) ? $_SESSION [ $n ] : $this -> random ( 10 ); $_SESSION [ $n ] = $s ; $values [ $n ] = $s ; } return $values ; }
-
Создайте метод random().
Эта функция генерирует случайную строку, используя случайный фал linux для большей хаотичности значений.
private function random ( $len ) { if ( function_exists ( 'openssl_random_pseudo_bytes' )) { $byteLen = intval (( $len / 2 ) + 1 ); $return = substr ( bin2hex ( openssl_random_pseudo_bytes ( $byteLen )), 0 , $len ); } elseif ( @ is_readable ( '/dev/urandom' )) { $f = fopen ( '/dev/urandom' , 'r' ); $urandom = fread ( $f , $len ); fclose ( $f ); $return = '' ; } if ( empty ( $return )) { for ( $i = 0 ; $i < $len ; ++ $i ) { if ( ! isset ( $urandom )) { if ( $i % 2 == 0 ) { mt_srand ( time () % 2147 * 1000000 + ( double ) microtime () * 1000000 ); } $rand = 48 + mt_rand () % 64 ; } else { $rand = 48 + ord ( $urandom [ $i ]) % 64 ; } if ( $rand > 57 ) $rand += 7 ; if ( $rand > 90 ) $rand += 6 ; if ( $rand == 123 ) $rand = 52 ; if ( $rand == 124 ) $rand = 53 ; $return .= chr ( $rand ); } } return $return ; }
-
Закончите класс закрывающей скобкой.
Это завершит класс csrf.
}
Реклама