Спецпроект «Базальт СПО». Развитие Open Source в России
Николай Костригин: «Мы создали Hantis, конвейер автоматизации. Проекты, исследуемые разными инструментами, переходят от одного исполнителя к другому, развиваются, возвращаются к автору, и так по кругу»
О том, как идет работа по повышению безопасности отечественного программного обеспечения, рассказывает
Речь пойдет об аутентификации на сайтах. Аутентификация – очень важная вещь, от нее зависит безопасность всего вашего проекта. Если система была продумана недостаточно хорошо, то в случае хранения приватной информации о проекте будут слагать истории на аналогах hacknet.ru о том, как получить чужие данные и управлять ими. Обычные почтовые системы сколько существуют, столько и исправляют свои системы аутентификации. К тому же система аутентификации может содержать систему восстановления пароля, что еще больше подрывает безопасность. На своем опыте приходилось открывать пару ящиков именно за счет слабой системы аутентификации. Не буду спорить, для новичков поломать mail.ru покажется невозможным, но это не так сложно. Речь далее пойдет не о взломе mail.ru, а о способах аутентификации и защиты от взлома.
Способы
Существует несколько стандартных способов аутентификации. Но любые способы основываются на какой-либо идентифицирующей информации. И чем меньше идентификационных данных, тем слабее защита. Например, аутентификация на основе лишь имени и пароля куда опаснее, чем если к этому добавится верификация по IP-адресу. Приведу несколько примеров, начиная с самого слабого:
Отсутствие аутентификации, знание нахождения нужных данных;
Аутентификация за счет передаваемых куков;
Аутентификация на основе имени и пароля;
Аутентификация на основе имени и пароля, IP-адреса;
Аутентификация на основе имени и пароля, времени, IP-адреса и т. п.
Такие методы сравнивать сложно, поскольку аутентификация может проходить однажды и на определенный срок, либо на каждый сеанс связи.
Удобство
Конечно, удобными являются те способы, которые не требуют какого-либо ввода данных и предустановки какого-либо программного обеспечения. К этому мы и будем стремиться, но в меру разумности. Наша основная задача – найти золотую середину, где количество аутентифицирующих действий компенсируется уровнем безопасности. Проблема создания безопасной системы в том, что необходимо учитывать удобство, а если сделать систему очень удобной, то это потребует снижения уровня безопасности и наоборот. Под удобством понимается количество необходимых действий для достижения удачной аутентификации. Тут существует несколько вариантов:
Ввод имени/пароля каждый раз.
Предустановка и настройка необходимого дополнительного ПО.
Знание секретного имени, например скрипта.
Полная прозрачность действий для клиента.
Самым удобным является последний вариант (полная прозрачность), но это означает, что идентифицирующие данные хранятся не в голове или записной книжке клиента, а в компьютере, например в cookie. Если аутентификация прозрачна лишь в небольшом промежутке времени, либо в течение одной сессии, то идентифицирующие данные могут быть просто в памяти, если было предустановлено ПО, то данные могут быть где угодно (винчестер, внешние носители и т. п.). Автоматизировать процесс получения чужих данных легче всего, когда они хранятся в cookie. Современные системы аутентификации комбинируют различные методы, поэтому автоматизировать что-то будет очень сложно. Система WebMoney предлагает хранить критичные данные на дискетке. Все обычные веб-сайты хранят обычные cookies, не заставляя пользователей сильно напрягаться.
Безопасность
Самый обычный вариант аутентификации, используемый на большинстве крупных сайтов: при входе на страницу пользователь аутентифицируется парой логин/пароль, после чего создается сессия, которая ограничивается либо закрытием браузера, либо временем. Сессия может привязываться к IP.
При получении почты у жертвы создана сессия, в это время жертве доступны все параметры ящика для чтения (кроме пароля). Таким образом жертва, зайдя на вашу страницу, сама того не зная, открывает в фреймах странички с параметрами, при этом отправляя их содержимое вам же. Это несложно реализуется примерно следующим скриптом (написанным на Perl), который вызывается из фрейма:
Приведенные скрипты требуют доработки и подходят только для некоторых версий Internet Explorer. Но вообще достать подобную информацию не составляет никакого труда, достаточно проштудировать следующие сайты:
и вы найдете все о том, как совершается атака на чужую информацию. (Врага надо знать в лицо.)
Рассмотрим более простой вариант аутентификации. Данный способ реализован у одного бывшего крупнейшего провайдера. Аутентификация происходит без использования cookie. Это заставляет пользователей постоянно вводить имя и пароль. Данная схема отбрасывает огромное число возможных дыр, но при этом подобная схема несколько нагромождает внутренний код рутинными операциями, при этом несложно допустить ошибку.
Рассмотрим схему подписки на получение логов. Раз аутентификация происходит без использования куков, то было бы логично сделать операцию получения логов в одной форме с аутентификацией, однако у провайдера это происходит в 2 шага:
Аутентификация.
Изменение параметров получения логов.
Возникает вопрос, каким образом мы на втором шаге узнаем о том, что именно хозяин логов делает изменения или просматривает информацию? Об этом заботится первый шаг следующим образом: после аутентификации (в случае успеха) на странице изменения параметров появляется скрытый атрибут:
где VALUE – имя пользователя. Больше никаких данных не требуется, что дает нам возможность, во-первых, перейти непосредственно ко второму шагу без аутентификации, а нужное имя придумать какое угодно, например любимой подруги. Данное свойство кривой аутентификации позволяет просматривать чужую статистику пользования Интернетом, телефоны и подобную приватную информацию.
Ошибкой mail.ru является присвоение уникального идентификатора сессии, не зависимого от времени или других случайных факторов. Это должно позволить получить доступ к почте следующим образом:
нам необходимы куки жертвы;
идентификатор сессии, который мы можем найти в переменной $ENV{"HTTP_REFERER"}, если жертва перейдет по ссылке на нашу страницу, также необходим;
мы должны знать примерное время, когда жертва будет проверять почту.
Затем, когда жертва заходит проверять почту, мы посылаем mail.ru запрос с куками жертвы и идентификатором. В течение получаса ящик будет в вашем распоряжении. Но я не утверждаю это, потому что сессия может быть привязана к IP, и тогда все накроется медным тазом (подмена IP-адреса – не такая простая задача). Наконец, мы начинаем примерно представлять схему работы идентификации.
При первоначальной аутентификации у клиента создается хэш (в куках), который зависит от: IP, времени, начала сессии, имени, пароля.
Хэш действует на протяжении одной сессии, в течение получаса (время зависит от вашего проекта) и отсылается при каждом запросе новой страницы вашего сайта. В данном случае возможна лишь аналогичная атака с mail.ru, но в составе с атакой spoofing, что реализуется несколько сложнее, и получение ответов от сервера затруднено принципом атаки (подмена IP).
По закрытию браузера, либо по истечении времени хэш приходит в негодность. Хэш можно раздавать всем друзьям и знакомым хакерам. Это им даст возможность подбирать параметры, в том числе и пароль, т.к. примерное время они могут знать, IP тем более. Значит, нужен еще один параметр. Чтобы подобрать пароль, нужно знать время, его можно угадать, но если сделать его точным до миллисекунд, то перебор становится затруднен.
Теперь подумаем немного. Пользователь присылает нам хэш. А нельзя ли исключить то, что у пользователя хранится этот хэш? Исключить это можно, передавая пользователю лишь идентификатор сессии. Все правильно, этим мы исключаем возможность подбора данных пользователя по хэшу, не теряя при этом ничего. Соответственно, данные, полученные от пользователя, мы ассоциируем с номером сессии, при этом пароль мы все же приводим в состояние хэша. Вот мы и получили безопасную схему аутентификации со своей стороны.
Остаются ошибки браузера. В данном случае возможна атака следующего вида: пользователь после прочтения «нехорошего» письма попадает на страницу взломщика, где уже скрыто в невидимые фреймы грузятся необходимые страницы, после чего содержимое страниц отправляется взломщику. Тут уже жертве придется просто-напросто ставить заплатки.
Микро-система
Давайте рассмотрим поближе, как должна работать система и приведем некоторые примеры, а начнем мы с того, что клиент заходит на главную страницу. Изначально у пользователя нет аутентифицирующих куков. Пользователь заполняет аутентифицирующие поля (Логин/Пароль) и отправляет следующую форму серверу:
<form action="cgi–bin/auth.cgi">
<input name="login" type="text">
<input name="password" type="password">
</form>
Скрипт теперь должен проверить, регистрировался ли тут такой пользователь или нет. Если не регистрировался, предложить повторить попытку или зарегистрироваться. Если полученные данные верны, тогда формируется сессия, а клиенту возвращается идентификатор в куках. Тут хочется отметить следующие моменты: обязательно проверяйте только POST-данные. Количество попыток ограничьте тремя, после чего просто заблокируйте аккаунт на некоторое непродолжительное время с данного IP (1-2 часа).
Предположим, что пришедшие данные лежат в хэше %POST (удобным в этом плане является модуль WebIn с сайта dklab.ru). В примере мы будем его использовать лишь для создания хэша с параметрами от пользователя %POST и %COOKIE. Тогда инициализация скрипта будет следующей:
use WebIn(1);
if (exists($COOKIE{id})) {CheckID()} # если в куках пришел параметр id тогда нужно его проверить
$ip=$ENV{REMOTE_ADDR};
# тут необходима проверка валидности IP и на заблокированные IP
$login=$POST{login};
$password=crypt($login,$POST{password});
($sec,$min,$hour,$mday,$mon,$year)
= (localtime(time))[0,1,2,3,4,5];
$mon+=1;
$hour="0$hour" if ($hour<10);
$min="0$min" if ($min<10);
$mday="0$mday" if ($mday<10);
$mon="0$mon" if ($mon<10);
$year+=1900;
$time=$year.$mon.$mday.$hour.$min.$sec;
Теперь четыре скаляра содержат необходимые для нас данные (логин, пароль, IP, время обращения).
Далее, нам необходимо прочитать имя, хэш пароля и сравнить их с полученными, для простоты представим, что пользовательские данные из базы уже лежат в скалярах $login_, $password_.
if ($login eq $login_ && $password eq $password_) {CreateID()}
else {WrongAuthorisation()}
При неудачной попытке авторизации увеличивается счетчик количества авторизаций, и в случае превышения лимита блокируется IP на некоторое время.
Теперь рассмотрим подробнее функцию &CreateID:
sub CreateID
{
return 0;
}
Данная функция содержит следующие шаги:
подготовка данных для создания сессии;
сохранение параметров сессии с самим номером сессии;
отправка кука с номером сессии.
Я не считаю необходимым навязывать способы форматирования данных, у каждого они свои, поэтому поговорим немного об уникальности сессий. Как вы сами понимаете, каждая сессия должна быть уникальной, и нельзя, чтобы номера сессий пересекались. Поэтому было бы хорошо, чтобы номер сессии зависел от параметров, ассоциированных с сессией. Время начала сессии – подходящий вариант, но это уже будет выдавать один из параметров, поэтому лучшим способом будет вести список сессий, по которому будет легко определить отсутствие номера сессии, а собственно номер сессии генериться случайно. Выудить полезную информацию не получится, а сворованный идентификатор сессии ничего не даст (опять же кроме сложной атаки с использованием spoofing IP).
Основной принцип: минимум критичной информации у пользователя и в передаваемых данных.
Если на вашем сайте авторизированные пользователи, например, только добавляют статью, а дальше их авторизация ни к чему, тогда лучшим вариантом будет вообще отсутствие работы с куками, и любое действие, разрешенное только избранным, должно идти параллельно с авторизацией.
И еще один момент: я рекомендую по минимуму использовать чужой код, а если уж используете, то вы должны представлять, что, где и как обрабатывается. Некоторые люди смело ставят такие вещи, как YABB либо чужие гостевые книги, в большинстве которых есть дыры. В том же YABB допускается вставка FLASH, а это уже признак того, что можно легко устроить XSS-атаку.
Еще один совет: чем больше код (ваш или чужой, а особенно чужой), тем больше вероятность ошибок в нем. Используйте только то, что действительно считаете необходимым.
Некоторые волшебные места
За последнее время находятся удивительные способы получения критичной информации. Если вы пишете собственную систему, то вам необходимо обратить внимание на следующий момент. Ответ от сервера в качестве результата аутентификации необходимо возвращать по истечении определенного времени, в среднем равного времени неудачной аутентификации. Что это значит? Просто по времени задержки можно узнать наличие логина в базе. Говоря простым языком, можно составить список пользователей, который в дальнейшем можно применять, например, для подбора паролей по словарю, либо использовать список, как готовый спам-лист. Реализуется задержка ответа достаточно просто: первым делом организуйте кэширизацию ответов. Неплохим примером может послужить модуль с dklab.ru (WebOut.pm), либо неплохой микро-пример на jkeks.far.ru/ret, модуль err.pm. Суть заключается в том, что весь вывод накапливается, после готовности данных они отправляются.
Другая менее популярная проблема небольших проектов может существовать в самом процессе обработки POST-запросов. Дело в том, что в HTML-форму можно положить собственный параметр.
<input name="login" type="file">
Собственно, речь идет о наличии не ASCII-символов. Необходимо иметь четкую и простую проверку, потому как данные логина сравниваются с содержимым базы, и нередко такие параметры передаются системам управления базами данных, где существуют свои критичные символы, т.е. необходим хороший фильтр данных. Кроме того, необходимо рассмотреть следующий пример:
Удивительный запрос, да? Логин приходит в виде файла? Проблема существует в некоторых обработчиках форм. Какие проблемы тут могут быть?
В логин попадут неотфильтрованные данные.
Атакующий сможет как минимум создать временный файл в системе, занять канал.
Это связано с универсальностью обработки входящих данных некоторых несложных модулей. Некоторые даже коммерческие буржуйские универсальные модули обработки входящих данных автоматически создают временные файлы перед тем, как определить необходимость этих данных, т.е. файлы сначала создаются, а затем уже скрипт решает, нужны ли эти данные или нет.
Данные проблемы ставят перед нами задачу. Оказывается, анонимные пользователи так же должны иметь сессии, их аутентификация происходит лишь по номеру сессии, который закреплен за IP-адрес. Это исключит DoS, но не DoS-атаки. Каждая сессия по своему завершению должна удалять временные файлы. Вообще было бы правильнее получать только те данные, которые мы запрашивали и именно того объема, который мы хотим.
Если на сервере используется правильный обработчик MIME, то последствия вообще сложно предсказать, потому как стандарт MIME предусматривает много каких вещей. Именно поэтому приходящие формы советую обрабатывать несложными алгоритмами уже упомянутых проектов. Кстати, cgi-lib так же неплох в этом отношении. Как вы понимаете, в данные стандарты заложена ошибка. Стандарт MIME предназначен для почтовых сообщений, а включение его в POST-ответы принесет немало бед, некоторые из них нам уже показала malware.com.
Хочется обратить ваше внимание на еще одну проблему, связанную с UNICODE и, собственно, Mozilla-браузером. Как известно, с настройками по умолчанию Mozilla отправляет данные формы в UNICODE, что значительно увеличивает объем данных. Тут проблемы вовсе неразрешимы средствами стандартов, так как однозначное определение UNICODE невозможно, потому как нет идентифицирующих UNICODE параметров нигде. Точнее, их может не быть. Анализировать приходящие данные на UNICODE нельзя, потому как нельзя будет избежать ошибок, а значит увеличится вероятность взлома. Рассмотрим пример содержимого POST от Mozilla:
Подобное содержимое должно преобразоваться из UNICODE, после чего пройти все фильтры по критичным символам и длине данных, но, как я и написал, однозначно нельзя определить UNICODE, поэтому входящие данные будут скорее испорчены. На этой оптимистической ноте я и хотел бы закончить свой рассказ о подводных камнях аутентификации через WEB.
Facebook
Twitter
Мой мир
Вконтакте
Одноклассники
Google+
Комментарии отсутствуют
Добавить комментарий
Комментарии могут оставлять только зарегистрированные пользователи