Данный выпуск продолжает тему постройки веб-сайта. До этого мы научились ставить и настраивать веб-сервер, базу данных, и сделали простой сайт с заметками.
Предыдущие части: Реляционная база данных
В каждом материале есть ссылка на предыдущие и следующий, так что если вы что-то пропустили, то можете до всего добраться потом.
Итак, многие сайты имеют зарегистированных пользователей. Сама регистрация заключается в том, чтобы заполнить форму с данными пользователя (как минимум это логин, пароль) и передать её на сайт. Движок сайта занесёт эти данные в таблицу базы данных и вот пользователь уже есть.
Впоследствии сайт должен определить, какой пользователь в данный момент запрашивает у него страницу.
Для этого пользователь должен "залогиниться" на сайт. Это неформальное слово, которое используется в повседневной речи, а вот официально...
Вы могли не раз видеть такие сообщения: "Для участия в акции авторизуйтесь на сайте..." Но этот термин, строго говоря, неправильный. Давайте разбираться.
Идентификация, Аутентификация, Авторизация
Это три разных понятия, которые все вместе составляют цепочку мер безопасности.
Когда пользователь проходит идентификацию, он просто говорит – я такой-то пользователь. Сделать это, например, можно с помощью идентификатора пользователя (назовём его user_id). Пользователь сообщает – у меня user_id=100, Сайт идентифицирует его как пользователя с user_id=100.
Но этого недостаточно. Идентифицировать себя можно и пользователем 100, и пользователем 200, то есть сообщить сайту не свой идентификатор, и стать другим пользователем, что очевидно небезопасно.
Поэтому пользователь должен, кроме идентификации, пройти аутентификацию. Это удостоверение его подлинности. Как вы могли заметить, к некоторым товарам прилагается сертификат подлинности (authenticity certificate), который собственно и подтверждает подлинность.
Смотрите: без сертификата вещь идентифицирует себя как сумка или часы известной фирмы, и мы можем этому верить или нет. Но с сертификатом мы уже точно знаем, что это подлинная вещь.
Для пользователя таким сертификатом может являться... да, электронный сертификат, ну а в более простом варианте это как раз логин и пароль. Так как пароль известен только пользователю, то введя его, пользователь подтверждает, что это именно он, настоящий.
То есть, вводя логин и пароль, мы не авторизуемся на сайте, а именно аутентифицируемся. Писать такое слово никто в здравом уме не будет, "залогиниться" это разговорное слово, но "авторизоваться" тоже неправильно, поэтому лучше писать по-человечески: "войдите на сайт".
Наконец, когда пользователь идентифицирован и аутентифицирован, наступает время авторизации. Авторизация аналогична слову "авторитет", то есть даёт некую власть или доступ к ресурсам. У кого больше авторитета, у того и доступ шире. Например, обычный пользователь, войдя на сайт, получает авторизацию на чтение форума и написание туда сообщений. Но пользователь с правами модератора получает также авторизацию на удаление сообщений, на бан пользователей и т.д.
В данный момент авторизация нас не интересует, так как мы рассматриваем только процесс логина на сайт.
Мы начинаем с "чистого листа", когда пользователь ещё не зашёл на сайт и сервер о нём ничего не знает.
Логин
Пользователь вводит логин и пароль и отправляет на сервер. Он пока не проходит идентификацию. Он только сообщил серверу, что знает вот такой логин и пароль. Сервер проверяет в базе таблицу пользователей. Он ищет в ней такого пользователя, у которого логин и пароль совпадают с теми, которые были присланы.
Найдя такую запись в таблице, сервер одновременно аутентифицирует и идентифицирует пользователя. То есть узнаёт, что у него user_id=100, допустим.
Теперь сервер может выполнить запрос пользователя и вернуть ему страницу в соответствии с его уровнем авторизации.
Сессии
Отдав страницу пользователю, сервер тут же забывает о нём. Канал связи закрывается, и сервер ждёт следующего запроса. То есть при следующем запросе пользователь должен опять аутентифироваться. Это, очевидно, неудобно.
Поэтому был придуман механизм сессий. Давайте разберём его на примере из жизни.
Есть такие места (выставки, рестораны, отели), где посетителям на руку надевают браслет. Посетитель проходит и идентификацию, и аутентификацию, и авторизацию. Он показывает свои документы, билет или оплаченный чек (идентификация + аутентификация) и получает браслет какого-то цвета (авторизация).
С этим браслетом посетитель может гулять по выставке, и даже выходить и заходить обратно. Ему не придётся снова платить или показывать документы. Сервис идентифицирует и авторизует его по браслету.
Выдача браслета пользователю – это открытие сессии. Пока сессия открыта, мы идентифицируем его по браслету, но уже не аутентифицируем. То есть другой человек может украсть браслет и пользоваться им. Но не зря они сделаны так, что снять их, не испортив, весьма проблематично.
Когда посетитель уходит насовсем и снимает браслет, сессия закрывается, и в следующий раз ему придётся заново аутентифицироваться.
Сервер выдаёт такие же электронные "браслеты" своим посетителям.
При получении данных логина и пароля и после идентификации пользователя сервер генерирует временный "браслет". Это просто случайная строка символов, которую невозможно повторить, например:
Tx9JzaeGqXceRoXorpgN
Далее сервер записывает у себя, что эта строка принадлежит пользователю с user_id=100. То есть, фактически, надевает этот "браслет" на пользователя.
Далее сервер возвращает эту строку (она называется идентификатор сессии, или session_id) пользователю. Пользователь получил "браслет" и теперь должен ходить на сервер с ним.
Для этого в каждом запросе к серверу нужно посылать и сам "браслет", то есть session_id. Например, это можно делать через GET-запросы. Но делать это руками опять же неудобно. Поэтому session_id и передаётся от сервера, и отправляется на сервер с помощью куки.
Этот механизм работает автоматически, и мы его уже рассматривали в материале Как работает веб-сайт: Заголовки, статусы и куки
Посылая куки с session_id, пользователь уже не должен аутентифицироваться при каждом запросе. Сервер принимает куки, и видит, что там записано:
session_d=Tx9JzaeGqXceRoXorpgN
И ищет у себя пользователя, на которого надет такой браслет, то есть к которому привязан такой session_id. Найдя его, сервер идентифицирует его как пользователя c id=100 и дальше может работать с ним как обычно.
Заметьте, что аутентификации уже нет. Пользователь идентифицирует себя с помощью session_id, но не подтверждает, что он это именно он. То есть другой пользователь, послав куки с таким же session_id, сможет идентифицировать себя как пользователя с user_id=100.
Опасно ли это? Да. Но на самом деле нет. Строка session_id очень сложная (сложнее пользовательского пароля, в большинстве случаев) и передавалась только на компьютер пользователя, который был аутентифицирован. Это секретная связь между сервером и компьютером пользователя. Если злоумышленник работает на другом компьютере, там этой строки нет. А узнать её или подделать гораздо сложнее, чем подобрать обычный пароль.
Сервер может хранить строку session_id сколько угодно, и куки на компьютере пользователя могут храниться сколько угодно. Поэтому, даже закрыв браузер и открыв его потом, пользователь всё равно останется аутентифицированным и сможет войти на сайт без логина и пароля.
На разных сайтах безопасность реализована по-разному, поэтому куки могут жить лишь ограниченное время, сессии на сервере могут "протухать", то есть тоже жить ограниченное время, и т.д. Так что конкретное поведение сайта зависит только от него самого.
Когда пользователь самостоятельно выходит с сайта (делает логаут, разлогинивается), то сервер удаляет у себя session_id и заставляет браузер удалить куки, так что ситуация возвращается к чистому листу.
Кроме того, пользователь может сам удалить куки в браузере. И несмотря на то, что на сервере сохранился session_id, он больше не будет приходить из куки (пользователь снял браслет), а значит, для сервера это то же самое, что отсутствие аутентификации.