C, PHP, VB, .NET

Дневникът на Филип Петров


* Автоматична автентикация с некриптирано cookie

Публикувано на 20 ноември 2008 в раздел ОСУП.

Нека разгледаме прост скрипт, в който автентикираме потребител. В началото на файла ще стартираме потребителска сесия (като абстрактно ще използваме създадената в предишните статии функция security_start_session), за да сме сигурни, че няма фиксиране на сесия. При първоначално зареждане ще се извежда форма, питаща потребителя за име и парола. Тя ще изпраща информацията чрез POST към същия скрипт. При положение, че сме въвели вярна комбинация (проверявано от функцията checklogin), то ще запишем в сесията поле "authenticated" със стойност "1". Чрез това поле ще накараме скрипта да следи, дали случайно не сме въвели вече вярно име и парола и ако да - няма да извежда формата на екрана. Ето и примерен код:

<?php
	function security_start_session($ssl, $timeout, $maxtime, $ip){
		// ... security checks where we may destroy the session
		session_start();
		session_regenerate_id(true);
		return 1;
	}
	if (security_start_session(0, 6*60, 20*60, 1) != 1){
		echo "<br>session destroyed!";
		return;
	}
	// Функция, която отпечатва формата в html кода
	function showloginform(){
		echo '<form action="cookie.php" method="POST">';
		echo 'user:';
		echo '<input type="text" name="user">';
		echo '<br>pass:';
		echo '<input type="password" name="pass">';
		echo '<br><input type="submit" name="submit"';
	}
	// Функция, която проверява за вярност на име и парола
	function checklogin($user, $pass){
                if(!is_string($user) || !is_string($pass)) return 0;
		if($user == "test" && $pass == "123456") return 1;
		else return 0;
	}

	// Ако вече сме автентикирани, то сървъра
	// е "запомнил" това в полето 'authenticated'
	if($_SESSION['authenticated'] == 1){
		echo '<html><head><title>WorldBank.dom login page</title></head><body>';
		echo "Welcome back. I remember your session...";
	}
	else{
		// Ако сме попълнили формата и сме натиснали Submit
		if( isset($_POST['submit'])){
			// Валидираме данните:
			if (checklogin($_POST['user'], $_POST['pass']) == 1){
				echo '<html><head><title>WorldBank.dom login page</title></head><body>';
				echo "You are logged in successfully!";
				$_SESSION['authenticated'] = 1;
			}
			else{
				echo '<html><head><title>WorldBank.dom login page</title></head><body>';
				echo "Invalid username and password";
			}
		}
		// В противен случай влизаме за първи път
		// и трябва да се изкара формата:
		else{
			showloginform();
		}
	}

?>
</body></html>

Големият недостатък тук, е че сесията е валидна до затварянето на браузъра на потребителя. За да го демонстрираме направете следният опит:
1. Отворете написаната страница и въведете вярно име и парола.
2. Отворете нов "tab" в браузъра със същата страница - ще забележите, че тя ви "помни".
3. Сега затворете браузъра напълно и отворете нов. Ще видите, че скрипта вече не ви "помни".

Както отбелязахме в много случаи е нужно да запазваме тази информация, за да може потребителя да влиза автоматично на нашия сайт. За целта ще използваме cookies:

<?php
	function security_start_session($ssl, $timeout, $maxtime, $ip){
		// ... security checks
		session_start();
		session_regenerate_id(true);
		return 1;
	}
	if (security_start_session(0, 6*60, 20*60, 1) != 1){
		echo "<br>session destroyed!";
		return;
	}
	function showloginform(){
		echo '<html><head><title>WorldBank.dom login page</title></head><body>';
		echo '<form action="cookie.php" method="POST">';
		echo 'user:';
		echo '<input type="text" name="user">';
		echo '<br>pass:';
		echo '<input type="password" name="pass">';

		// Добавяме html checkbox
		echo '<br>Set cookie: ';
		echo '<input type="checkbox" name="remember" value="true">';

		echo '<br><input type="submit" name="submit"';
	}

	function checklogin($user, $pass){
		if ($user == "test" && $pass == "123456") return 1;
		else return 0;
	}

	// Проверяваме дали имаме записано cookie
	if(isset($_COOKIE['user']) && isset($_COOKIE['pass'])){
		// ако да - ще проверим дали данните в него са валидни
		if (checklogin($_COOKIE['user'], $_COOKIE['pass']) == 1){
			$_SESSION['authenticated'] = 1;
		}
		// Ако не са - ще ги изтрием
		else{
			setcookie("user","", mktime(12,0,0,1, 1, 1970));
			setcookie("pass","", mktime(12,0,0,1, 1, 1970));
		}
	}

	if($_SESSION['authenticated'] == 1){
		echo '<html><head><title>WorldBank.dom login page</title></head><body>';
		echo "Welcome back. I remember your session...";
	}
	else{
		if( isset($_POST['submit'])){
			if (checklogin($_POST['user'], $_POST['pass']) == 1){
				// Ще "запомним" ли сесията с cookie?
				if($_POST["remember"]=="true"){
					setcookie("user",$_POST['user'], time()+3600);
					setcookie("pass",$_POST['pass'], time()+3600);
				}
				echo '<html><head><title>WorldBank.dom login page</title></head><body>';
				echo "You are logged in successfully!";
				$_SESSION['authenticated'] = 1;

			}
			else{
				echo '<html><head><title>WorldBank.dom login page</title></head><body>';
				echo "Invalid username and password";
			}
		}
		else{
			showloginform();
		}
	}

?>
</body></html>

В този си вид модела на автентикация е относително сигурен. За cookie променахме, че най-големият проблем, е когато то се пренася през некриптиран канал. В случая бихме казали, че преди написаната функция secure_session_start(...) се грижи за контрола на канала на трафика. Това обаче е изключително грешен подход. Представете си, че разработвате приложение в екип от програмисти, като вие разработвате модула за управление на cookies, а ваш колега управлението на сесиите. Трябва ли вашият код да зависи от сигурността на кода на вашия колега? Ако погледнете отново кода ще видите, че дори в нашия пример сме задали стойност "0" на $ssl при извикването на security_session_start()!!! Не е ли по-добре да се погрижите и да се "преосигурите" с малко допълнителна защита? При сигурното програмиране параноята е полезна.

Горният код има и друг сериозен проблем със сигурността. Казахме, че cookies са файлове с обикновен текст. Ние не записахме ли паролата в него? Какво ще се случи ако някой успее да открадне това cookie от компютъра на наш потребител? Очевидно е че той ще има възможност за достъп до нашата система, но все пак не бихме искали поне да скрием истинският вид на паролата чрез някаква криптография. А можем ли да следим дали едно cookie е откраднато или не?

В следващата статия ще разгледаме методи за защита на cookies използвани за автентикация.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*