О чем топик?
В этой статье я расскажу о реализациях разного функционала (преимущественно, на веб-сервисах) для обеспечения безопасности пользователей на примере «гигантов» современной IT индустрии. Данный материал будет полезен разработчикам, архитекторам, тим-лидам и менеджерам при постановке задач схожего функционала. Реализации в статье разработаны командами профессионалов, проверены временем и сотнями миллионами пользователей (а также большим количеством хакеров), хоть и никаких гарантий, что именно данный вариант реализации — абсолютно правильный и 100% безопасный, конечно же нет. Информация основана на личном анализе этих ресурсов.
Авторизация
Наиболее удачный и интересный вариант реализован в ВК. Описывал вкратце здесь. Пароль вводится на главной странице сайта, но action формы ведёт на поддомен (login.vk.com), там выставляется кука для текущего домена (login.vk.com) и для vk.com (remixsid). Если с кукой на «главном» домене что-то не то (изменена, не совпал последний IP и т.п), автоматически происходит редирект на login.vk.com. И если пароль действительно вводился в этом браузере, то в нём будет persistent-кука (которая выставилась при вводе пароля), по которой произойдет автоматический вход. Если же её нет (к примеру, куки увели через XSS) то на аккаунт не пустит. Так же ведется запись последних активных сессий — 6 штук, который считаются «живыми» и которые можно завершить в личном кабинете, что очень удобно. У гугла тоже отдельный домен для авторизации. И так как у него много различных сервисов, то при авторизации ещё передается список сервисов, куда пускать с этими cookie.
Двухфакторная авторизация
О ней говорят налево и направо и в общем случае принято реализовывать OTP отсылкой через SMS. Снова в пример возьмем Google. И проблема первая: связь не доступна, что делать пользователю? Для этого реализовали два решения:
- Оффлайн генерация OTP через приложение на мобильном устройстве. Первым шагом идёт синхронизация веб-сайта и мобильного приложения, вводом специального кода. После пароли на сервере и на мобильном телефоне сопоставляются по времени (лучше, чтобы телефон был синхронизирован по NTP). Т.е. на мобильном устройстве, в оффлайне, выводится пароль, который подойдет в качестве OTP (каждую минуту — новый пароль). В итоге в любом месте, при рабочем мобильном устройстве мы можем залогиниться без получения SMS/принятия звонка от Google.
- Разовые, уже сгенерированные, пароли. На странице accounts.google.com/b/0/SmsAuthSettings можно получить и распечатать пароли, которые всегда (по одному разу) подойдут при запросе OTP кода. Можно распечатать и положить в бумажник
Авторизация сотрудников Google на их внутреннем портале login.corp.google.com также происходит с использованием двухфакторной авторизации, но можно еще использовать usb-токен (аналогия с банками) для авторизации.
А что делать, если Ваш сервис предоставляет API для мобильных устройств? И некоторые приложения, работающие вне браузера, несовместимы с двухэтапной аутентификацией и не могут запрашивать коды подтверждения? Здесь же, по примеру Google, решили проблему следующим образом. Можно сгенерировать «пароль приложения». Вводится имя приложения и разово выдается (больше нигде и никогда не отображется) пароль для приложения, который нужно ввести вместо пароля.
Восстановление пароля
Логичным продолжением будет этот пункт. Используя стандартную схему с высылкой ссылки на почту, что лучше делать, генерировать новый пароль самому или дать возможность ввести его пользователю? Вообще, более предпочтителен второй способ (Google). Но если Вы решили использовать первый — генерируйте пароль ну никак не менее 7-8 символов (буквы/цифры/хотя бы один спец. символ). Буквально на днях анализировал таблицу с пользователями и паролями, где пароль выставлялся автоматом (md5, 6 символов, [a-zA-Z0-9]). И за копейки получал их в чистом виде. Да и вообще, рекомендовано: sha* и две «соли». (т.е. вида sha*($stat_salt.$password.$email)), т.е. когда при полном дампе базы данных ни один пароль всё равно не получится расшифровать, так как будет неизвестна статичная «соль» (которая, например, зашита в коде). Но это тема другого разговора.
Важно еще понимать, что нужно еще и правильно его реализовать. Пример: Facebook, прошлый год. Восстановление пароля через SMS. Нам присылают код на телефон, мы его вводим и меняем id конечного пользователя в форме. В итоге — меняем пароль любому юзеру. Как можно было не проверять ID юзера, которому мы меняем пароль? Как можно было не сопоставлять высланный код в SMS и id пользователя? Epic fail.
Защита от CSRF
Защиту от CSRF верно реализовывать с помощью «скрытых» токенов (<input type = «hidden»>). Но как их верно генерировать? Google, при каждой авторизации, выдает токен на сессию и сохраняет её в Cookie. Т.е. смотрит cookie, смотрит, что пришло в форме, если всё ок — работаем дальше. То есть один токен на все действия в рамках одной сессии. Неправильно спрашивать пользователя при несовпадении токенов, действительно ли он хотел выполнить это действие («привет» разработчикам сервиса, которые только что узнали себя в этой статье), так как это очень сомнительно (пользователь может кликнуть автоматом ) + есть обходы подобных «просьб с уточнениям». Вконтакте поступили по другому — они генерируют на каждое действие один токен, который основывается на id текущего пользователя, id действия и некоторого id «цели» (пользователь, номер сообщества/паблика и т.п.). Но, к сожалению, не везде его проверяют.
Отдельный домен для контента
Весь пользовательский контент нужно заливать на отдельный домен. Это может спасти от множества угроз. У Google это googleusercontent.com, у VK — vk.me. На примере статьи XSS'им iOS устройства на примере софта от Facebook, Google, ВКонтакте, когда «особенность» целой платформы для эксплуатации уязвимости не может нанести никакого вреда — ещё один показатель, чем важен отдельный (изолированный, никаких cookie) домен для пользовательского контента.
Content Security Policy
Сейчас многие ресурсы активно ведут разработку с учетом CSP. Например Yandex не так давно реализовал вариант почты с полной поддержкой CSP. CSP — это такой заголовок, который сообщает браузеру, откуда (с каких адресов) и какой контент (картинки, скрипты) можно загружать. В итоге, когда атакующий даже находит способ провести XSS атаку, ему не удаётся переслать какие-либо данные напрямую на другой сервер, или вообще выполнить inline скрипты. Конечно, находятся и обходы, например можно сгенерировать картинку и встроить в неё js и, при возможности, залить на один из разрешенных доменов. И обратиться к ней <script src "...image.gif>, пример.
HSTS
Говоря снова о HTTP заголовках (статья), нельзя не упомянуть о HSTS. Одно дело просто его отправлять.
Другое дело, что существует pre-shared лист в Chrome и Firefox, среди которых перечислены домены, которые в обязательном порядке нужно посещать через HTTPS — src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.json.
Можно отправить заявку на добавление вашего ресурса на почту
Аккаунты на 3rd-party ресурсах
Довольно часто (а порой и необходимо) обращаться к услугам других сервисов (регистрация доменов, мониторинг и т.п.). И вроде как существует цикл (например, раз в 3 месяца) когда на всех подобных ресурсах меняется пароль. Хорошая практика.
Возможно где-то еще у «гигантов» (у меня нет информации) используется доступ по VPN до рабочих ресурсов (частая практика и в маленьких компаниях) и какие-нибудь еще механизмы защиты. Если знаете таковые — делитесь в комментариях :)
upd: Возможно, что Apple использует VPN.
Автор: BeLove