Вход на сайт через Вконтакте

Аутентификация на основе токенов

Аутентификация на основе токенов в последние годы стала очень популярна из-за распространения одностраничных приложений, веб-API и интернета вещей. Чаще всего в качестве токенов используются Json Web Tokens (JWT). Хотя реализации бывают разные, но токены JWT превратились в стандарт де-факто.

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

Процедура аутентификации на основе токенов:

Авторизация через вконтакте, и другие для самых начинающих — 1

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

Итак, начнем с ВКонтакте. Заходим на

страницу подключения сайта

, в дальнейшем настройки подключенного сайта будут доступны вам на странице

управления приложениями

, там мы узнаем ID приложения и секретный ключ, который естественно раскрывать никому нельзя.

На странице, на которой предполагается кнопочка «Войти через ВКонтакте» требуется добавить в head страницы

<scripttype="text/javascript"src="http://userapi.com/js/api/openapi.js?34"></script>

И инициализировать приложение:

VK.init({apiId: __APP_ID___});

Теперь нужно показать пользователю кнопку через вызов виджета. В качестве параметров Auth принимает id элемента, в который нужно отобразить виджет, ширину и адрес страницы, куда мы будем перенаправлены после попытки доступа.

      <divid="vk_auth"></div>
<scripttype="text/javascript">
VK.Widgets.Auth("vk_auth", {width: "300px", authUrl: '/vklogin.php?'});
</script>

Что увидит пользователь:

Вход на сайт через Вконтакте

После щелчка на «Войти через ВКонтакте» пользователя кидает на страницу вида vkontakte.ru/widget_auth.php?act=a_auth_user&app=__APP_ID__&hash=d2d47b3c85d1a091a8, затем на url, указанный вами в параметре AuthUrl при вызове виджета. Кидает со следующими GET параметрами:
first_name (имя), hash (используется для проверки того действительно ли запрос пришел от контакта, а не хакер Вася пытается авторизоваться под чужими данными), last_name (Фамилия), photo (большая аватарка, 119 пикселей шириной), photo_rec (маленькая аватарка, 50х50), uid (id пользователя). Пришедшие к нам параметры я после фильтрации сохранил с такими же именами в глобальной области видимости.
Теперь нам нужно сделать скрипт vklogin.php, в котором мы будем проверять правильность пришедших данных и, либо авторизовывать пользователя если он уже есть в нашей базе, либо создавать новый аккаунт для пользователя зашедшего к нам впервые.

if ($_REQUEST['hash']==md5('2445355'.$uid.'__SECRET_KEY__')) {
//доверяем вконтактику, и далее полагаем, что пользователь действительно авторизован там
//для учетных записей пользователей я решил выделить логины вида vk-********
$result = mysql_query("SELECT id, random, password FROM tracker_users WHERE username = 'vk-$uid'");
setcookie('uid','');
setcookie('pass','');
if (mysql_num_rows($result)) {
//пользователь авторизован, просто пересоздадим куки
$user = mysql_fetch_assoc($result);
mysql_query("UPDATE tracker_users SET name = '$name' WHERE username = 'vk-$uid' LIMIT 1");
setcookie('pass',md5($user['random'].$user['password'].$user['random']));
setcookie('uid',$user['id']);
} else {
//добавим запись в таблицу пользователей
$random = mt_rand(100000,999999);
$pwd = $uid . 'verysecretlonglongword-';
$pid=md5(uniqid(rand(),true));
mysql_query("INSERT INTO tracker_users
(username, name, password, random, id_level, email, style, language, flag, joined, lastconnect, pid, time_offset) VALUES
('vk-$uid', '$name', '"
. md5($pwd) . "', $random, 3, '', 5, 7, 0, NOW(), NOW(),'$pid', '0')");
//вставили строчку, теперь создадим куки и перебросим на другую страницу
setcookie('pass',md5($random.md5($pwd).$random));
setcookie('uid',mysql_insert_id());
}
header("Location: /index.php");
}

* This source code was highlighted with Source Code Highlighter.

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

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

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

Вход на сайт через Вконтакте

Если уровень и тематика статьи интересна хабрапользоватям, то я продолжу с майл.ру, facebook и твиттером.

Вторая часть. Mail.ru

«а вк взломать можешь?» – интернет-безопасность [статья первая]

Авторизация с помощью учетной записи во «вконтакте»

С помощью аккаунта в социальной сети «ВКонтакте» можно авторизоваться на vhod-v-lichnyj-kabinet.ru без регистрации и ввода пароля. Для этого достаточно нажать на логотип данной соцсети при входе на сайт.

Шаг 1. Выберите нужный способ авторизации:

Вход на сайт через Вконтакте

Шаг 2. В открывшемся окне выполните одно из двух действий:

— введите логин и пароль к вашему профилю во «ВКонтакте», если вы в данный момент не залогинены в этой соцсети;
Вход на сайт через Вконтакте

— либо разрешите приложению доступ к вашей информации, если вы уже залогинены во «ВКонтакте».
Вход на сайт через Вконтакте

Обратите внимание! Вы не сообщаете сайту vhod-v-lichnyj-kabinet.ru свой логин и пароль от аккаунта во «ВКонтакте». Авторизация происходит при помощи протокола OAuth. Этот способ авторизации совершенно безопасен для данных вашего профиля в соцсети (см. «Вопросы и ответы»).

Шаг 3. Для завершения авторизации введите адрес вашей электронной почты (как отмечалось выше, HeadHunter не получает ваш пароль и логин во «ВКонтакте» — поэтому почту нужно ввести еще раз).

Вход на сайт через Вконтакте

Шаг 4а. Если на vhod-v-lichnyj-kabinet.ru уже существует учетная запись с подобным адресом, то вы получите об этом уведомление. Введите пароль к своему кабинету на vhod-v-lichnyj-kabinet.ru, чтобы связать эти две учетные записи и в дальнейшем без проблем авторизовываться с помощью аккаунта во «ВКонтакте».

Вход на сайт через Вконтакте

Вы авторизованы! И ваша учетная запись синхронизирована с учетной записью «ВКонтакте». Теперь вы будете входить на vhod-v-lichnyj-kabinet.ru нажатием одной кнопки «Войти через ВКонтакте».

Шаг 4б. Если у вас раньше не было регистрации на vhod-v-lichnyj-kabinet.ru, то при заходе через «ВКонтакте» у вас есть возможность импортировать данные о своем образовании, дате рождения и городе прямо из профиля.

Вход на сайт через Вконтакте

Теперь вы не только авторизованы на vhod-v-lichnyj-kabinet.ru, но у вас даже есть заготовка под резюме: все основные пункты уже заполнены!

Аутентификация в соцсетях

Уверен, эта картинка знакома всем:

Аутентификация или авторизация?

Некоторые путают термины «аутентификация» и «авторизация». Это разные вещи.

Ещё тут?

Поздравляю, вы успешно дочитали длинную, нудную и скучную статью.

Беспарольная аутентификация

Первой реакцией на термин «беспарольная аутентификация» может быть «Как аутентифицировать кого-то без пароля? Разве такое возможно?»

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

Беспарольная аутентификация — это способ конфигурирования процедуры входа и аутентификации пользователей без ввода паролей. Идея такая:

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

Есть похожий метод, при котором вместо одноразовой ссылки по SMS отправляется код или одноразовый пароль. Но тогда придётся объединить ваше приложение с SMS-сервисом вроде twilio (и сервис не бесплатен). Код или одноразовый пароль тоже можно отправлять по почте.

И ещё один, менее (пока) популярный (и доступный только на устройствах Apple) метод беспарольной аутентификации: использовать Touch ID для аутентификации по отпечаткам пальцев. Подробнее о технологии.

Если вы пользуетесь Slack, то уже могли столкнуться с беспарольной аутентификацией.

Двухфакторная аутентификация (2fa)

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

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

Демонстрация


На видео показано, как страница «злоумышленника» на домене

Как это выглядело

В принципе, процесс получения пользовательского Access Token’а страницей злоумышленника происходил по стандартной схеме эксплуатации CSRF-уязвимости:

Немного о vk open api

Выдержка из официальной документации:

Open API — система для разработчиков сторонних сайтов, которая предоставляет возможность легко авторизовывать пользователей ВКонтакте на Вашем сайте. Кроме этого, с согласия пользователей, вы сможете получить доступ к информации об их друзьях, фотографиях, аудиозаписях, видеороликах и прочих данных ВКонтакте для более глубокой интеграции с Вашим проектом.

Т.е. это JS библиотека, позволяющая работать с VK API (авторизация, вызов методов API, вроде ‘wall.post’, ‘audio.get’, ‘video.add’, etc…) прямо со страницы вашего сайта. Для того, чтобы использовать эту библиотеку, необходимо создать VK-приложение с типом «Веб-сайт», указать домен в настройках, и разместить пару тегов script на странице.

Переход на новый уровень: webworkers

Через некоторое время после того, как я отправил последнее демо, уязвимость исправили. И снова, я решил попробовать разобраться, как именно исправили уязвимость.

Как и раньше, для получения Access Token’а пользователя делался JSONP-запрос на сервер VK, и в ответе была всё та же сверка текущего домена с доменом приложения VK:

Подключение библиотеки

Пример подключения и инициализации библиотеки:

Порочный jsonp


Давайте подробнее рассмотрим работу метода

VK.Auth.getLoginStatus()

. Для того, чтобы получить Access Token, делается JSONP-запрос на следующий URL:

Принцип проверки авторизации пользователя

Для работы с VK API из JS-кода веб-страницы, используется метод

VK.Api.call()

, например:

Эксплуатация уязвимости


Тогда я решил проверить, а что если определить для

location.hostname

геттер, который будет всегда возвращать строку

Выводы

Порой инструмент, которым пользуешься на протяжении долгого времени, преподносит сюрпризы. Иногда в виде серьёзных уязвимостей. Однако есть общее правило: никогда не передавайте через JSONP конфиденциальные данные. Даже когда код валидации получателя JSONP-ответа кажется безупречным, выясняется, что можно подменить браузерное окружение JS (BOM) так, что вся проверка перед передачей токена коду страницы сводится на нет. Вообще, пора отказываться от JSONP в пользу CORS.

В этой публикации, я ни в коем случае не хотел выставить разработчиков VK Open API в нехорошем свете. Наоборот: ребята молодцы, разрабатывают крутой сервис, на крутых технологиях с отличной документацией и службой поддержки. А ошибиться может каждый.

В принципе, это всё. Я планировал описать суть уязвимости в нескольких абзацах, однако после написания каждого абзаца меня не покидало чувство недосказанности. Так и получилась эта пелена текста.

Благодарю за внимание!

Похожее:  Формы для сайта: юзабилити форм и рекомендации по его улучшению

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *