Ставим пароль на страницу. Установка пароля на страницу Вход по паролю скрипт html
Одна из основных аксиом защиты информации гласит - "комфортность системы обратно пропорциональна её защищённости". Это значит, что при выборе системы защиты необходимо найти оптимальное соотношение сложности защиты и удобства работы пользователей.
С другой стороны, разработка и внедрение защиты требует определённых затрат сил и средств. Следовательно, надо разумно подходить к проектированию защиты. Проще говоря, не надо делать сложную и дорогостоящую систему защиты, если на сайте не хранится ничего ценного. Ни один злоумышленник не полезет ломать вашу домашнюю страничку, сайт-визитку небольшой компании или сайт детского сада.
В предыдущем уроке мы рассматривали авторизацию средствами Web-сервера (Basic-авторизация). Наверное, это самый лёгкий и самый безопасный способ ограничения доступа к ресурсам. Однако, сопровождение такого механизма достаточно трудоёмко, особенно при большом количестве пользователей с различными правами. Кроме того, не все сервера позволяют использовать HTTP-авторизацию.
Более популярная альтернатива - парольная защита. Смысл её в том, что на сервере хранятся списки пользователей и соответствующие им логины, пароли и права доступа. При первом обращении к сайту пользователь вводит логин/пароль и получает доступ к ресурсам. Сервер "запоминает" пользователя и не спрашивает пароль до следующего открытия сессии (перезапуска браузера).
Организация парольной защиты целиком и полностью ложится на плечи программиста. Разработчик должен сам обеспечить безопасность хранения списков пользователей, проверку логинов/паролей, сохранение контекстов безопасности и их повторное использование. Под контекстом безопасности здесь понимается набор параметров, однозначно определяющих пользователя (как минимум это логин, пароль и идентификатор сессии).
Рассмотри пример реализации простейшей парольной защиты. Создадим файл logon.php
При нажатии на кнопку "вход" данные формы будут отправлены на сервер, там скрипт проверит введённые логин и пароль и если они равны "admin" и "megaPass" соответственно - отобразит сообщение, что вход разрешен. Если логин или пароль не верны - пользователь увидит предупреждающее сообщение.
Первый недостаток этого скрипта: передача данных методом GET. При использовании этого метода данные передаются непосредственно в адресе, а значит видны даже невооруженным глазом. Например, если вы ввели правильные логин и пароль, то в адресной строке увидите
Http://localhost/logon.php?login=admin&passwd=megaPass
Второй недостаток: имена пользователей и пароли зашиты прямо в код. Это значит, что для добавления новых пользователей вам надо будет постоянно менять код файла. А представьте себе, какого размера будет файл, если у вас на сайте хотя-бы тысяча зарегистрированных пользователей... Списки пользователей лучше всего хранить в отдельном файле, а лучше в базе данных, т.к. злоумышленнику файл украсть намного проще, чем добывать что-то из базы данных.
Третий недостаток: результаты входа пользователя не запоминаются, т.е. достаточно обновить страницу и вас снова попросят ввести пароль.
Итак, рассмотрим способы устранения этих недостатков.
Скрыть передаваемые данные проще всего используя метод передачи POST. В этом случае браузер сам (скрытно от пользователя) передаст серверу все необходимые данные и перехватить их можно будет только специальными программами из арсенала IT-специалистов, программистов или хакеров.
Как говорилось выше, списки пользователей надо хранить отдельно. Создадим таблицу в тестовой базе данных:
CREATE TABLE `smplusers` (
`user_id` int(11) NOT NULL auto_increment,
`user_name` varchar(50) NOT NULL,
`user_login` varchar(50) NOT NULL,
`user_password` varchar(50) NOT NULL,
`reg_date` datetime NOT NULL,
PRIMARY KEY (`user_id`)
)
и добавим в неё несколько записей пользователей:
INSERT INTO smplUsers
(user_name, user_login, user_password, reg_date)
values
("Иванов И.И.", "ivanov-i-i", "pass1", NOW()),
("Петров П.П.", "petrovich", "pass2", NOW()),
("Сидоров С.С.", "sidorov", "pass3", NOW())
Обратите внимание, что оператор INSERT допускает одновременное добавление в таблицу сразу нескольких записей, при этом данные перечисляются блоками через запятую.
Теперь изменим logon.php таким образом, чтобы имя пользователя и пароль корректно проверялись непосредственно в базе данных:
// здесь подключаемся к базе данных
// $link - ссылка на подключение
$link = mysql_connect("localhost", "db_user", "db_passwd");
mysql_select_db("db_name", $link);
?>
$login = mysql_real_escape_string($login);
$passwd = mysql_real_escape_string($passwd);
If($login != "" || $passwd != "")
{
$sql = "SELECT * FROM smplUsers
WHERE user_login = "$login"
AND user_password = "$passwd"
LIMIT 1";
$qry = mysql_query($sql, $link);
if($qry)
{
if(mysql_num_rows($qry) > 0)
{
echo "Доступ разрешен
" . "\n";
echo "Пользователь: " . $row["user_name"];
}
else
echo "Доступ запрещен!";
}
}
else
echo "Введите логин и пароль";
?>
Теперь логин и пароль передаются скрытно, а учётные данные очень просто изменить, отредактировав таблицу в базе данных. Остался последний штрих - научить сервер запоминать факт регистрации. Проще всего сделать это при помощи механизма сессий. Внесём необходимые изменения:
session_start();
if(!$_SESSION["user_id"])
$_SESSION["user_id"] = -1;
// здесь подключаемся к базе данных...
?>
...
if(mysql_num_rows($qry) > 0)
{
echo "Доступ разрешен
" . "\n";
$row = mysql_fetch_array($qry);
echo "Пользователь: " . $row["user_name"]; $_SESSION["user_id"] = $row["user_id"]; $_SESSION["user_name"] = $row["user_name"];
}
... } else echo "Здравствуйте, " . $_SESSION["user_name"];
?>
Теперь сервер будет запоминать каждого пользователя, успешно вошедшего в систему, а при следующем обновлении страницы будет выводиться приветственное сообщение.
Это скрипт - лишь пример организации парольной защиты, пусть и вполне функциональный. Сделать из него практически ценный образец можно, добавив проверку вводимых данных, функции шифрования, восстановения пароля, завершения сессии и др.
Пароли являются основным средством защиты информации и используются на компьютере повсеместно – от входа в учетную запись до авторизации на страничках в социальных сетях. У активного пользователя различных ключей безопасности набирается столько, что все их держать в памяти невозможно. Тут-то на помощь и приходит функция сохранения паролей в настройках браузера.
Работает она следующим образом:
- Вы открываете какой-то сайт, где требуется регистрация.
- Вводите данные для авторизации в своем профиле.
- Браузер предлагает вам сохранить введенную информацию – вы соглашаетесь.
При следующем запуске этого сайта вам не нужно ничего вводить; даже если вы вышли из аккаунта, все строки формы авторизации будут заполнены. Но здесь обнаруживается серьезный недостаток – давайте узнаем, как посмотреть пароль, закрытый звездочками, и можно ли вообще это сделать.
Итак, вы заходите на сайт и видите пароль под звездочками. Казалось бы, удобная штука – нажимаете «Войти» и ничего больше вводить не нужно, а другие пользователи ваш пароль не видят.
Пароль, закрытый звездочками, – легкая добыча для взлома.
Проверьте это на своем компьютере. В качестве примера используем браузер Google Chrome:
Точно так же можно посмотреть ключи доступа к аккаунтам в других браузерах – Mozilla Firefox, Opera, Internet Explorer. Посмотрим, как это делается в Mozilla для закрепления материала:
Кстати, менять значение обратно на «password» необязательно. Если вы закроете страницу, а затем снова зайдете на неё, то увидите, что звездочки вернулись. Однако теперь вы знаете, какие они ненадежные защитники личных данных.
Настройки браузеров
Если вы думаете, что на этом разоблачение звездочек окончено, то глубоко ошибаетесь. Во всех браузерах есть еще более удобный способ посмотреть пароль, который вы сохранили при первой авторизации на сайте. На этот раз для примера возьмем веб-обозреватель Opera:
Появится окошко, в котором будет много адресов сайтов и данные от разных аккаунтов. На первый взгляд всё хорошо: логины, конечно, отображаются, но вместо паролей знакомые нам звездочки. Однако если вы нажмете на одну строку, то увидите, что рядом со звездочками появляется кнопка «Показать» .
Одно нажатие – и вы видите ключ безопасности от сайта. Можно раскрыть все пароли, сделать скриншот и вы даже не поймете, что ваши запароленные странички теперь в опасности. Подобной информацией делится не только Opera, но и другие браузеры. В Google Chrome, например, такую табличку можно вызвать следующим способом:
В Mozilla Firefox таблица со всеми сохраненными ключами доступа открывается в разделе настроек «Защита».
В других браузерах ситуация похожая – в открытом доступе обязательно есть все данные, которые вы соглашаетесь сохранить.
Использование специального софта
Но не только браузеры хранят данные о пользователях, которые тот сам любезно предоставляет и сохраняет.
Любая программа, в которой требуется ввод пароля и логина, тоже предлагает запомнить эти данные, чтобы не вводить их при каждом запуске.
Соответственно, есть специальные утилиты, позволяющие эти сохраненные данные посмотреть. Работают такие утилиты по одному принципу, поэтому возьмем в качестве примера программу Password Cracker. Распространяется она бесплатно, а весит смешные 45 Кб.
В строке «Пароль» в окне утилиты Password Cracker появится сохраненный ключ безопасности в цифро-буквенном отображении.
Вывод
Как вы видите теперь, узнать сохраненный в браузере пароль, закрытый звездочками, не представляет никакого труда. Нужен лишь доступ к компьютеру и пара минут времени, чтобы данные от ваших аккаунтов оказались в руках посторонних лиц.
Конечно, в таком случае вы рискуете забыть пароль и не попасть в нужный профиль. Однако это не страшно: мы уже писали о том, как восстановить пароль на Gmail, как узнать пароль от Wi-Fi, как вернуть доступ к аккаунту в игре WarFace и т.д. Если вы можете зайти в почтовый ящик, на который зарегистрирован акканут, или привязали к профилю номер телефона, то при необходимости сможете легко восстановить забытый пароль.
Но что делать с теми ключами безопасности, которые вы уже сохранили в настройках браузера? Правильный ответ – удалить. Когда вы просматривали пароли через настройки, то должны были увидеть, что функцию сохранения кодов можно отключить. Очистите таблицы с сохраненными ключами, удалив все строки, а затем деактивируйте саму функцию.
Нет похожих статей.
Я решил описать способы закрыть паролем часть сайта. Тема, на самом деле, большая, поэтому на первый раз ограничусь авторизацией php+mysql.
Самый первый вопрос, который обычно встаёт - как закрыть директорию со скриптами администрирования паролем. При этом не нужно никаких изысков - один или несколько администраторов имеют одни и те же права, а персоналии меняются редко. Проще всего в данной ситуации использовать стандартную серверную авторизацию - положить файлы.htaccess и.htpasswd и прописать в них нужные параметры. Про это уже написано много, поэтому я ничего особо нового не скажу.
Добавлю две вещи. Первое - это куда класть файл.htpasswd. Экспериментальным путем я выяснил, что если, например, путь к документу с сообщением об ошибке (ErrorDocument) пишется относительно системной переменной DocumentRoot. Но путь к файлу с паролями (UserFile) пишется относительно ServerRoot. Насколько я понял, выше ServerRoot положить.htpasswd нельзя - "../" не воспринимается. Всё это сделано для того, чтобы можно было поместить файл с паролями, например, одним уровнем выше корневой директории сайта, чтобы из сети доступа к файлу не было вообще.
Второе - это то, что скрипт может узнать, кто его открывает и пароль: переменные $PHP_AUTH_USER и $PHP_AUTH_PW.
Главный недостаток этого способа - сервер не может блокировать подбор пароля (это после нескольких неудачных попыток входа пользователю предлагается подождать часок-другой, а в течение этого времени обращения с его IP-адреса игнорируются). Это написано в официальной документации по Апачу.
Ещё один недостаток - необходимость переписывать файлы с паролями при удалении пользователя или введении нового. Но если это происходит нечасто, этого способа вполне достаточно, к тому же не придётся забивать голову написанием механизма авторизации.
Автоматизация авторизации
Это нужно не только для упрощения работы с большим количеством пользователей и их большой "текучкой". Если нужно держать дополнительную информацию о пользователях, либо необходимо гибкое разграничение прав, лучше перенести авторизацию в базу.
Каждая страница закрытой территории подключает файл с вот таким кодом:
$result = mysql_query(" SELECT * FROM person WHERE login="". preg_replace("/[^w_-]/","",$PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm="User area""); header("HTTP/1.0 401 Unauthorized"); print("Чтобы войти в пользовательскую часть сайта, надо ввести имя и пароль."); exit(); }; $user_row = mysql_fetch_array($result);
В первой строке из логина удаляются все символы кроме букв, цифр, тире и символа подчеркивания. Затем проверяется количество полученных строк, и только если это одна строка, дается доступ. В остальных случаях пользователь увидит в броузере окно, предлагающее ввести логин и пароль. Если же пользователь вошел успешно, в массиве $user_row мы имеем всю информацию о нем.
Конечно же, пример, который я привёл, имеет ряд существенных недостатков. Не переписывайте его один-в-один, чтобы потом не пасть жертвой попыток подбора пароля, потому что
1. защиты от подбора здесь нет
2. если таблица пользователей большая, при подборе пароля злоумышленник, скорее всего, "завалит" базу
И последний на сегодня способ - хранение зашифрованных данных в куках.
Есть скрипт для входа, остальные подключают код, позволяющий только продолжить действия в закрытой области - если куки истекут, или он выйдет оттуда, придётся возвращаться на страницу для входа.
Входной скрипт проверяет логин и пароль и выдает две куки. В первой - логин, чтобы сразу опознать пользователя (в базе поле логина, естественно, уникальное или даже ключевое). Во второй куке - хэш от времени входа и пароля (для полноты конспирации я добавляю к этим строкам букву "Ы" - тогда хэш подобрать почти невозможно:).
Все остальные программы подключают код, который делает следующее. Делает запрос в базу - выбирает строку с полученным логином. Из этой строки берет поле "log_time" и пароль и делает из них, как и описано выше, хэш. Сравнивает его с тем, что получил, и если они совпадают, выдает новую куку хэша, опять же, от пароля, времени и буквы "Ы" и делает запрос в базу данных "UPDATE user SET log_time=’…’ WHERE login=’$cookie_login’".
if (isset($HTTP_COOKIE_VARS[$cookie_login]) && isset($HTTP_COOKIE_VARS[$cookie_code])) { $login = $HTTP_COOKIE_VARS[$cookie_login]; $code = $HTTP_COOKIE_VARS[$cookie_code]; $result = mysql_query("SELECT date_format(log_date,"%Y%m%d%H%i%s") as log_date1,pass,uid FROM user WHERE email="$login" AND log_date>"DATE_SUB(NOW(),INTERVAL 15 MINUTE)""); if (!mysql_error() && @mysql_num_rows($result)==1) { $log_time0 = time(); $log_time1 = date("YmdHis", $log_time0); $log_time2 = date("Y-m-d H:i:s", $log_time0); $current_user = mysql_fetch_array($result); if (md5($current_user["pass"].$current_user["log_date1"].$md5letter) == $code) { mysql_query("UPDATE user SET log_date="$log_time2" WHERE uid=".$current_user["uid"]); setcookie($cookie_code, md5($current_user["pass"].$log_time1.$md5letter), time()+900, $site_path); $auth = true; } else unset($current_user); }; };
Опять же, здесь нет никакой защиты от подбора и атаки на сервер (кстати, здесь можно вместо буквы "Ы" писать IP-адрес пользователя - чтобы, например, соседу по офису нельзя было взять файл с кукой и зайти со своего компьютера).
Пароль на страницу. Часть 2. Блокировка подбора
Когда я выложил этот выпуск в прошлый раз, меня запинали на месте, мол такой блокировкой можно и сервер "пустить под откос".
Но сначала о блокировке подбора. Банальности, но всё-таки. Пароль длинной десять символов из букв латиницы и цифр — это очень много вариантов. Если подбирать пароль по 1 000 000 вариантов в секунду, понадобится несколько тысяч лет. Но поскольку такую абракадабру запомнить сложно, мы чаще делаем пароль из осмысленных слов. Несколько лет назад оказалось, что большинство паролей можно подобрать при помощи словаря из 10 000 слов. В своё время в сети появился червь (вирус такой), который лазил по юниксовым серверам, используя их дырки в защите, и подбирал пароли привелигированых пользователей при помощи… системного орфографического словаря Юникса. Ничего таскать не надо было!
Каждый пользователь, пока он не ввёл правильный логин и пароль, считается злобным хакером. С чем же мы имеем дело, когда пользователь вводит что-либо неправильно?
забывчивость (на это на приличных сайтах есть формочка "забыл пароль", чтобы отправить на введёный в системных настройках email этот самый пароль)
баловство ("ибо нефиг")
подбор пароля по словарю (вероятность удачного подбора велика, поэтому закрывать надо, тем более, если сайт коммерческого характера)
DoS-атака (чтобы не перегрузить сервер, надо минимизировать действия, которые будет выполнять скрипт в таком случае)
Я долго думал, как можно вызвать перегрузку на сервере, если механизм защиты стоит на файлах. Оказалось, несложно (сколько это будет стоить — другой вопрос). Итак, допустим, сервер не выдержит, если скрипт будет пытаться 1000 раз в секунду открывать файлы на запись и писать в них данные. Поскольку после 5 неудачных попыток войти в систему пользователь будет сразу получать отказ в доступе (без какой-либо записи данных в файл), надо найти 200 уникальных IP, с которых по пять раз и обратиться. Это возможно. Вешаем в баннерокрутилке html-баннер с пятью тегами:
Пользователь моментально делает пять обращений сервер пять раз пишет в файл (кстати, в некоторых броузерах, возможно, выскочит окно для ввода логина и пароля). Можно сделать html-страницу с пятью такими картинками, а саму страницу вставить через iframe на посещаемый сайт (через iframe — чтобы по полю referer не нашли. Вряд ли служба поддержки халявного хостинга будет заниматься такими вещами как копание в лог-файлах в поисках рефереров). Те примеры, которые я привёл, разумеется, натянуты, но сам факт того, что можно воспользоваться таким недостатком системы, доказан. Кстати, нечто подобное уже было.
Но всё-таки приведу этот способ — зря писал, что ли? Его, кстати, можно без особого страха применять для ограниченного количества адресов (например, для локальной сети фирмы), положив в директорию файл.htaccess такого содержания:
order deny,allow
deny from all
allow from xxx.xxx.xxx
А вот код программы:
$errors = 0; $fn = "ignore/". preg_replace("[^d.]", "", $REMOTE_ADDR. ".". $HTTP_FORWARDED_FOR); if (is_file($fn)) { if (filectime($fn) < time()-3600) unlink($fn); else $errors = fread(fopen($fn, "r"), 2); }; if ($errors>5) { print ("Доступ закрыт. Зайдите через час."); exit(); }; // здесь происходит установка связи с сервером БД. чтобы не трогать зря, если пользователя сразу же "отлупили". $result = mysql_query("SELECT * FROM user WHERE login="". preg_replace("/[^w_-]/", "", $PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm="secret area""); header("HTTP/1.0 401 Unauthorized"); print ("Authorization required"); fwrite(fopen($fn, "w"), ++$errors); exit(); }; $current_user = mysql_fetch_array($result); mysql_free_result($result); Впрочем, грех работать с файлами, если есть база. Шутка. Для непрошедших авторизаций создаём таблицу: CREATE TABLE unauth (username VARCHAR(64) NOT NULL, pass VARCHAR(64) NOT NULL, ip VARCHAR(255), logintime TIMESTAMP) И вместо обращения к файлам работаем с базой. $errors = @mysql_result(mysql_query("SELECT count(username) as falses FROM unauth WHERE logintime>DATE_SUB(NOW(),INTERVAL 1 HOUR) AND ip="$REMOTE_ADDR""),0); if (mysql_error()) die(mysql_error()); if ($errors>5) { print ("Доступ закрыт. Зайдите через час."); exit(); }; $result = mysql_query("SELECT * FROM user WHERE login="". preg_replace("/[^w_-]/", "", $PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm="secret area""); header("HTTP/1.0 401 Unauthorized"); print ("Authorization required"); mysql_query("INSERT INTO unauth (username, pass, ip) VALUES ("$PHP_AUTH_USER", "$PHP_AUTH_PW", "$REMOTE_ADDR $HTTP_X_FORWARDED_FOR")"); exit(); }; $current_user = mysql_fetch_array($result); mysql_free_result($result);
Хранить ли старые записи для статистики или нет — дело хозяйское. Если что, их можно удалять, выполняя перед авторизацией запрос:
DELETE FROM unauth WHERE logintime Такой механизм при больших нагрузках будет работать быстрее и надёжнее, чем файлы — в базе часто используемые данные буферизуются и обрабатываются непосредственно в оперативной памяти. Была у меня в своё время проблема: надо закрыть администрационную часть сайта, но при этом я не могу положить файл.htpasswd выше корневой директории сайта. Врождённая подозрительность не позволяла положить файл с паролем и отдельную директорию и заблокировать доступ к ней по http. Решил попробовать сделать защиту как в phpMyAdmin: у пользователя спрашиваются логин и пароль, с которыми скрипт соединяется с базой. В своём анализаторе логов я сделал именно так. Удобство метода в том, что файл можно складывать куда угодно - никаких кук, никаких директив сервера для директории. Заодно, если поменяется пароль в базе данных, не надо ничего исправлять в скрипте.Пароль на страницу. Часть 3. Пароль от базы