Як захиститися від атак з використанням міжсайтової підробки запиту (CSRF) в php

Атака з використанням міжсайтової підробки запиту – CSRF)-це тип уразливості веб-програми, коли жертва ненавмисно запускає скрипт у своєму браузері, який використовує поточну сесію авторизованого користувача в певному сайті. Атаки CSRF можуть проводитися через get або POST запити. Дана стаття покаже вам, як захистити свій веб-додаток від атак CSRF.

Метод

Ми будемо використовувати два методи для захисту від CSRF атак ваших GET і POST запитів.

Перший метод полягає у використанні випадкового ключа при кожному запиті, це унікальна рядок, що генерується для кожної сесії. Ми генеруємо ключ, а потім включаємо його в кожну форму у вигляді прихованого поля. Далі, система перевіряє валідність форми, порівнюючи ключ і значення, що зберігається в сесійної змінної користувача. Тобто, якщо зловмисник захоче згенерувати запит, він повинен буде знати значення ключа.

Другий метод-це використання випадкових назв для кожного поля форми. Значення випадкового імені для кожного поля зберігається в сесійній змінній і після того, як форма відправлена (стався сабміт), система генерує нові випадкові назви полів. Тобто, якщо зловмисник захоче зробити атаку, йому потрібно буде знати ці випадкові назви полів форми.

Наприклад, запит, який раніше виглядав ось так:

Буде виглядати ось так:

Метод1 З 2:
Створення файлу csrf.class.php

Це основний файл, який буде містити всі методи, необхідні для запобігання атак CSRF.

  1. Створіть файл csrf.class.php. Почніть, створивши файл, і збережіть його з наступним вмістом:

    &#lt;?php
    
    Class Csrf {
    
    Весь код в цій секції керівництва буде додано в кінці цього файлу.
  2. Створіть метод get_token_id ().
    ця функція отримує id ключа (токен) з сесійної змінної, якщо ж він ще не був створений, то вона генерує випадковий токен.

    Public Function Get_token_id() {
    	If(Isset($_SESSION['token_id'])) { 
    		Return $_SESSION['token_id'];
    	} Else {
    		$token_id = $this-&#gt;Random(10);
    		$_SESSION['token_id'] = $token_id;
    		Return $token_id;
    	}
    }
    
  3. Створіть метод get_token ().
    ця функція отримує значення токена, якщо ж значення ще не було згенеровано, то воно генерується.

    Public Function Get_token() {
    	If(Isset($_SESSION['token_value'])) {
    		Return $_SESSION['token_value']; 
    	} Else {
    		$token = Hash('sha256', $this-&#gt;Random(500));
    		$_SESSION['token_value'] = $token;
    		Return $token;
    	}
    
    }
    
  4. Створіть метод check_valid ().
    ця функція перевіряє на валідність id і значення токена. Перевірка відбувається шляхом порівняння значень, отриманих при get або POST запитах зі значеннями, що зберігаються в сесійної змінної користувача.

    Public Function Check_valid($method) {
    	If($method == 'post' || $method == 'get') {
    		$post = $_POST;
    		$get = $_GET;
    		If(Isset(${$method}[$this-&#gt;Get_token_id()]) &#amp;&#amp; (${$method}[$this-&#gt;Get_token_id()] == $this-&#gt;Get_token())) {
    			Return True;
    		} Else {
    			Return False;	
    		}
    	} Else {
    		Return False;	
    	}
    }
    


  5. Створіть метод 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-&#gt;Random(10);
    		$_SESSION[$n] = $s;
    		$values[$n] = $s;	
    	}
    	Return $values;
    }
    


  6. Створіть метод 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&#lt;$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&#gt;57)
    				$rand+=7;
    			If ($rand&#gt;90)
    				$rand+=6;
    
    			If ($rand==123) $rand=52;
    			If ($rand==124) $rand=53;
    			$return.=Chr($rand);
    		}
    	}
    
    	Return $return;
    }
    


  7. Завершіть клас закриваючою дужкою.
    це завершить клас csrf.

    }
    
    Тепер ви можете закрити файл csrf.class.php, так як ми з ним закінчили.

Метод2 З 2:
Захист сторінок за допомогою csrf.class.php

Ці кроки покажуть вам, як використовувати клас CSRF для захисту від атак CSRF.

  1. Захист POST форми.наведений нижче код показує використання класу csrf для форми.

    &#lt;?php
    Session_start();
    Include 'csrf.class.php';
    
    $csrf = New Csrf();
    
    
    / / генерація id і значення токена
    $token_id = $csrf-&#gt;Get_token_id();
    $token_value = $csrf-&#gt;Get_token($token_id);
    
    / / Генерація випадкових назв для полів форми
    $form_names = $csrf-&#gt;Form_names(Array('user', 'password'), False);
    
    
    If(Isset($_POST[$form_names['user']], $_POST[$form_names['password']])) {
    	// перевіряємо чи є валідними id і значення токена.
    	If($csrf-&#gt;Check_valid('post')) {
    		/ / отримуємо змінні форми.
    		$user = $_POST[$form_names['user']];
    		$password = $_POST[$form_names['password']];
    		
    		/ / Метод форми йде тут
    	}
    	/ / генеруємо нове випадкове значення для форми.
    	$form_names = $csrf-&#gt;Form_names(Array('user', 'password'), True);
    }
    
    ?&#gt;
    
    &#lt;form action="index.php" method="post"&#gt;
    &#lt;input type="hidden" name="&#lt;?= $token_id; ?&#gt;" value="&#lt;?= $token_value; ?&#gt;" /&#gt;
    &#lt;input type="text" name="&#lt;?= $form_names['user']; ?&#gt;" /&#gt;&#lt;br/&#gt;
    &#lt;input type="text" name="&#lt;?= $form_names['password']; ?&#gt;" /&#gt;
    &#lt;input type="submit" value="Login"/&#gt;
    &#lt;/form&#gt;
    


Ще почитати: