Сегодня поговорим об авторизации

Авторизация - предоставление определённому лицу или группе лиц прав на выполнение определённых действий; а также процесс проверки (подтверждения) данных прав при попытке выполнения этих действий.[1][2][3] Часто можно услышать выражение, что какой-то человек «авторизован» для выполнения данной операции — это значит, что он имеет на неё право.

Авторизацию не следует путать с аутентификацией: аутентификация — это процедура проверки легальности пользователя или данных, например, проверки соответствия введённого пользователем пароля к учётной записи паролю в базе данных, или проверка цифровой подписи письма по ключу шифрования, или проверка контрольной суммы файла на соответствие заявленной автором этого файла. Авторизация же производит контроль доступа легальных пользователей к ресурсам системы после успешного прохождения ими аутентификации. Зачастую процедуры аутентификации и авторизации совмещаются.

Т. е. авторизация нужна для предоставления пользователю каких либо прав, приведем пример.

Начнем с примера. Скажем, мы хотим добавить возможность оставлять комментарии к странице: пользователь вводит свое имя, e-mail, адрес домашней странички (и другую информацию о себе), наконец, текст сообщения, и после нажатия кнопки его мысль отправляется в путешествие по проводам и серверам, чтобы в конце концов попасть в некую базу данных на нашем сервере и остаться там на веки вечные. М-да...

Теперь предположим, что эта наша страница — довольно часто посещаемое место, у нее есть постоянные пользователи, которые несколько раз на дню оставляют там свои сообщения. Что же — им придется каждый раз вводить свое имя, адрес электронной почты и другую информацию в пустые поля? Как бы сделать так, чтобы это все запоминалось где-то, и даже при следующем запуске браузера нужные поля формы инициализировались автоматически, разумеется — у каждого пользователя индивидуально,

НЕ нашли? Не то? Что вы ищете?

тем, чем он заполнил их ранее?

Чтобы этого добиться, в принципе существуют два метода. Оба они имеют как достоинства, так и недостатки, и вскоре мы увидим, в чем же они заключаются.

Первый способ: хранить на сервере отдельную базу данных, в которой для каждого пользователя по его IP-адресу можно было бы получить последние им же введенные данные. В принципе, это решение довольно универсально, однако, у него есть два существенных недостатка, которые сводят на нет все преимущества. Главный из них — большинство пользователей не имеют фиксированного (как говорят, статического) IP-адреса — каждый раз при входе в Интернет он назначается им (провайдером) автоматически (сервер провайдера обычно имеет контроль над несколькими десятками зарезервированных IP-адресов, доступных для пользователя, и выбирает для него тот, который еще не занят кем-то еще). Таким образом, мы вряд ли сможем определить, кто на самом деле зашел в нашу гостевую книгу. Второй недостаток мало связан с первым — дело в том, что если ваших пользователей очень много, то довольно проблематично в принципе иметь такую базу данных, ведь она занимает место на диске, не говоря уж об издержках на поиск в ней.

Второй способ подразумевает использование cookies. Cookie — это небольшая именованная порция информации, которая хранится в каталоге браузера пользователя (а не на сервере, заметьте!), но которую сервер (а точнее, сценарий) волен в любой момент изменить. Кстати, сценарий также получает все cookies, которые сохранены на удаленном компьютере, при каждом своем запуске, так что он может в любой момент времени узнать, что же там у пользователя установлено. Самым удобным в cookies является то,

что они могут храниться недели и годы до тех пор, пока их не обновит сервер или же пока не истечет срок их жизни (который тоже назначается сценарием при создании cookie). Таким образом, мы можем иметь cookies, которые "живут" всего несколько минут (или до того момента, пока не закроют браузер), а можем — "долгожителей".

Сначала хотелось бы сказать пару слов насчет самого термина cookies (это множественное число, произносится как "кукис" или, более "русифицировано", "куки"). В буквальном переводе слово звучит как "печенье", и почему компания Netscape так назвала свое изобретение, не совсем ясно. А поскольку писать "печенье" несколько неудобно, чтобы не вызывать несвоевременных гастрономических ассоциаций, везде, где можно,

мы будем применять именно слово cookies, во множественном числе и мужского рода.

Кстати, в единственном числе это понятие записывается cookie и произносится на русский манер — "кука".

Не правда ли, последний способ представляет собой идеальное решение для нашей проблемы? Действительно, теперь сценарию достаточно получить у пользователя его данные, запомнить их в cookies (как это сделать — см. разд. "Установка cookie" далее в этой главе), а затем работать, будто ничего и не произошло. Конечно, перед выводом HTML-документа формы обязательно придется проставить значения value для некоторых элементов (которые, ясно, извлечены из соответствующих cookies).

Однако не все так гладко. Конечно, и у этой схемы есть недостатки, главный из которых заключается в том, что каждый браузер хранит свои cookies отдельно. То есть cookies, установленные при пользовании Chrome, не будут "видны" при работе в FireFox, и наоборот. Однако, согласитесь, все же это почти не умаляет достоинств cookies — в конце концов, обычно пользователи работают только в одном из перечисленных браузеров.

Но мы несколько отклонились от темы. Как уже упоминалось, каждому cookie сопоставлено время его жизни, которое хранится вместе с ним. Кроме этого, имеется также информация об имени сервера, установившего этот cookie, и URL каталога, в котором находился сценарий-хозяин в момент инициализации (за некоторыми исключениями).

Зачем нужны имя сервера и каталог? Дело в том, что сценарию передаются только те cookies, у которых параметры с именем сервера и каталога совпадают с хостом и каталогом сценария соответственно (ну, на самом деле каталог не должен совпадать полностью, он может являться подкаталогом того, который создан для хранения cookies).

Так что совершенно невозможно получить доступ к "чужим" cookies — браузер просто не будет посылать их серверу. Это и понятно: представьте себе, сколько ненужной информации передавалось бы сценарию, если бы все было не так (особенно если пользователь довольно активно посещает различные серверы, которые не прочь поставить ему свой набор cookies). Кроме того, "чужие" cookies не предоставляются в целях защиты

информации от несанкционированного доступа — ведь в каком-то cookie может храниться, скажем, важный пароль (как часто делается при авторизации), а он должен быть доступен только одному определенному хосту.

Установка cookie

Мы подошли к вопросу: как же сценарий может установить cookie в браузере пользователя? Ведь он работает "на одном конце провода", а пользователь — на другом. Решение довольно логично: команда установки cookie — это просто один из заголовков ответа, передаваемых сервером браузеру. То есть, перед тем как выводить Content-type, мы можем указать некоторые команды для установки cookie. Выглядит такая команда следующим образом (разумеется, как и всякий заголовок, записывается она в одну строку):

    Set-Cookie: name=value; expires=дата; domain=имя_хоста; path=путь; secure

Существует и другой подход активизировать cookie — при помощи HTML-тега <meta>. Соответственно, как только браузер увидит такой тег, он займется обработкой cookie.

Формат тега следующий:

<meta http-equiv="Set-Cookie" content="name=value; expires=дата; domain=имя_хоста; path=путь; secure">

Мы можем видеть, что даже названия параметров в обоих способах одинаковы. Какой из них выбрать — решать вам: если все заголовки уже выведены к тому моменту, когда вам потребовалось установить cookie, используйте тег <meta>. В противном случае лучше взять на вооружение заголовки, т. к. они не видны пользователю, а чем пользователь меньше видит при просмотре исходного текста страницы в браузере — тем

лучше нам, программистам.

ПРИМЕЧАНИЕ

Возможно, вы спросите, нахмурив брови: "Что же, с точки зрения программиста хороший пользователь — слепой пользователь?" Тогда мы ответим: "Нет и еще раз нет! Такой пользователь хорош лишь для дизайнера, для программиста же желателен пользователь безрукий (или, по крайней мере, лишенный клавиатуры и мыши)".

Вот что означают параметры cookie.

_ name Вместо этой строки нужно задать имя, закрепленное за cookie. Имя должно быть URL-кодированным текстом, т. е. состоять только из алфавитно-цифровых символов. Впрочем, обычно имена для cookies выбираются именно так, чтобы их URL-

кодированная форма совпадала с оригиналом.

_ value Текст, который будет рассматриваться как значение cookie. Важно отметить, что этот текст (так же, как и строка названия cookie) должен быть URL-кодирован. Таким образом, мы должны отметить неприятный факт, что придется писать еще и функцию URL-кодирования (которая, кстати, раза в два сложнее, чем функция для декодирования, т. к. требует дополнительного выделения памяти).

_ expires Необязательная пара expires=дата задает время жизни нашего cookie. Точнее, cookie самоуничтожится, как только наступит указанная дата. Например, если задать expires=Sunday, 2-Feb-17 15:52:00 GMT

то "печенье" будет "жить" только до 2 февраля 2017 года. Кстати, вот вам и вторая неприятность: хорошо, если мы знаем наверняка время "смерти" cookie. А если нам нужно его вычислять на основе текущего времени (например, если мы хотим, чтобы cookie существовал 10 дней после его установки, как в подавляющем большинстве

случаев и происходит)? Придется использовать функцию, которая формировала бы календарную дату в указанном выше формате. Кстати, если этот параметр не указан, то временем жизни будет считаться вся текущая сессия работы браузера до того момента, как пользователь его закроет.

_ domain

Параметр domain=имя_хоста задает имя хоста, с которого установили cookie. Ранее мы уже говорили про этот параметр. Так вот, оказывается, его можно менять вручную, прописав здесь нужный адрес, и таким образом "подарить" cookie другому хосту. Только в том случае, если параметр не задан, имя хоста определяется браузером

автоматически.

_ path

Параметр path=путь обычно описывает каталог (точнее, URI), в котором расположен

сценарий, установивший cookie. Как мы видим, этот параметр также можно задать

вручную, записав в него не только каталог, а вообще все, что угодно. Однако при

этом следует помнить: указав хост, отличный от хоста сценария, или путь, отличный

от URI каталога (или родительского каталога) сценария, мы тем самым никогда

больше не увидим наш cookie в этом сценарии.

_ secure

Этот параметр связан с защищенным протоколом передачи HTTPS, который в книге

не рассматривается. Если вы не собираетесь писать сценарии для проведения банковских операций с кредитными карточками (или иные, требующие повышенной безопасности), вряд ли стоит обращать на него внимание.

После запуска сценария, выводящего соответствующий заголовок (или тег <meta>),

у пользователя появится cookie с именем name и значением value. Еще раз напоминаем:

значения всех параметров cookie должны быть URL-кодированы, в противном случае возможны неожиданности.

Получение cookies из браузера

Получить cookies для сценария несколько проще: все они хранятся в переменной окружения HTTP_COOKIE в таком же формате, как и QUERY_STRING, только вместо символа амперсанда & используется точка с запятой ;. Например, если мы установили два cookies:

cookie1=value1 и cookie2=value2, то в переменной окружения HTTP_COOKIE будет сле-

дующее:

cookie1=value1;cookie2=value2

Сценарий должен разобрать эту строку, распаковать ее и затем работать по своему усмотрению._

Теперь при первом заходе на этот URL пользователь получит форму с пустым полем для ввода имени. Если он что-то туда напечатает и нажмет кнопку отправки, его информация запомнится браузером. Итак, посетив в любое время до 2 февраля 2017 года этот же URL, он увидит то, что напечатал давным-давно в текстовом поле. И, что самое

важное, — его информацию "увидит" также и сценарий. Кстати, у злоумышленника нет никаких шансов получить значение cookie посетителя, потому что оно хранится у него на компьютере, а не на сервере.

Но не будем забегать вперед. Займемся пока теорией авторизации.

Аутентификация

Часто бывает нужно, чтобы на какой-то URL могли попасть только определенные пользователи. А именно только те, у которых есть зарегистрированное имя (login) и пароль (password). Механизм аутентификации как раз и призван упростить проверку данных

таких пользователей.

ПРИМЕЧАНИЕ

Часто в процессе получения доступа к какому-либо ресурсу выделяют две стадии: аутентификацию — подтверждение личности пользователя (например, по соответствию пары "логин/пароль", соответствию открытого ключа закрытому) и авторизацию — подтверждение прав пользователя на запрашиваемый ресурс или действие.

Мы не будем здесь рассматривать все возможности этого механизма по трем причинам.

Во-первых, существует довольно много типов аутентификации, различающихся степенью защищенности передаваемых данных. Во-вторых, при написании обычных CGI-сценариев для того, чтобы включить механизм аутентификации, необходимо провести

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

унифицируется при использовании PHP, и вам не придется ничего исправлять в этих злополучных настройках сервера. Так что давайте отложим практическое знакомство с авторизацией и займемся ее теорией.

Расскажем вкратце о том, как все происходит на нижнем уровне при одном из самых

простых типов авторизации — basic-аутентификации. Итак, предположим, что сцена-

рий посылает браузеру пользователя следующий заголовок:

WWW-Authenticate: Basic realm="имя_зоны" HTTP/1.0 401 Unauthorized        

Обратите внимание, что последний заголовок несколько отличается по форме от обычных заголовков. Так и должно быть. Строка имя_зоны в первом из них задает некоторый идентификатор, определяющий, к каким ресурсам будет разрешен доступ зарегистрированным пользователям. При программировании CGI-сценариев этот параметр используется в основном исключительно для формирования приветствия (подсказки) в диалоговом окне, появляющемся в браузере пользователя (там отображается имя зоны).

Затем, как обычно, посылается тело документа (сразу отметим, что именно это тело ответа будет выдано пользователю, если он нажмет в диалоговом окне кнопку Cancel, т. е. отменит вход). В этом случае происходит нечто удивительное: в браузере пользователя появляется небольшое диалоговое окно, в котором предлагается ввести зарегистрированное имя и пароль. После того как пользователь это сделает, управление передается обратно серверу, который среди обычных заголовков запроса (посылаемых

браузером) получает примерно такой:

Authorization: Basic TG9naW46UGFzcw==

Это не что иное, как закодированные данные, введенные пользователем. Теоретически, далее этот заголовок должен каким-то образом передаться сценарию (для этого как раз и необходимо добавление команд в файлы конфигурации сервера). Сценарий, декодировав его, может решить: или повторить всю процедуру сначала (если имя или пароль

неправильные), или же начать работать с сообщением "OK, все в порядке, Вы — зарегистрированный пользователь".

Предположим, что сценарий подтвердил верность данных и "пропустил" пользователя.

В этом случае происходит еще одна вещь: login и password пользователя запоминаются в скрытом cookie, "живущем" в течение одной сессии работы с браузером. Затем, что бы мы ни делали, заголовок

Authorization: Basic значение_cookie

будет присылаться для любого сценария (и даже для любого документа) на нашем сервере. Таким образом, посетителю, зарегистрировавшемуся однажды, нет необходимости каждый раз заново набирать свое имя и пароль в течение текущего сеанса работы с браузером, т. е. пока пользователь его не закроет.

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

можно ее задействовать для определения, какой же посетитель зарегистрировался.__