Форма аутентификации

Соображения безопасности во время аутентификации

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

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

Заставьте своих пользователей выбирать надежные пароли! Хорошая политика паролей делает нецелесообразными атаки методом грубой силы и словаря, то есть угадывание пароля пользователя с помощью ручных или автоматизированных средств. Наиболее важным ограничением является установка минимально допустимой длины в 8 символов, и это следует делать всегда. Помимо этого, вот несколько общих ограничений, которые пытаются обеспечить адекватный пароль с минимальной сложностью:

  • Смесь прописных и строчных букв.
  • Смесь букв и цифр.
  • Хотя бы один специальный символ: !@#$%^&*() и т.д.

Тем не менее, он был найден исследование, спонсируемое Национальным институтом стандартов США (NIST) США ¹ из того, что пользователи склонны реагировать на эти дополнительные ограничения очень предсказуемым образом. Например, если пользователь намеревался использовать пароль «пароль», но столкнулся с вышеуказанными ограничениями, он, скорее всего, изменил бы свой пароль на предсказуемый «Пароль1!».
NIST предлагает сравнить пароль с черным списком недопустимых паролей и отклонить совпадающие пароли. Цитировать:

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

NIST
Сообщение об ошибке, предлагающее пользователю выбрать более надежный пароль

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

Если вы ожидаете, что ваши пользователи будут говорить на языках, которые либо используют нелатинский алфавит, либо расширенную латиницу (с диакритическими знаками или специальными буквами, такими как ø, æ, œ), теоретически разрешение использования полной палитры символов Unicode повысит безопасность. Это предотвратит большинство атак грубой силы, которые в любом случае предполагают стандарты ASCII, а также значительно увеличит количество возможных комбинаций². Хотя это может показаться пустяком, на практике вы должны учитывать, что вы можете неправильно обрабатывать UTF-8 (например, обрабатывать канонически эквивалентные символы). Неправильная обработка Unicode может снизить удобство использования и даже негативно сказаться на безопасности. Делайте это только в том случае, если вы уверены в своих силах.
И последнее замечание: важно установить ограничение на максимальную длину. Невыполнение этого требования может подвергнуть вас риску длинный пароль ДОС атака. 64 символа — хороший верхний предел.

Хеширование паролей

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

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

Чтобы сохранить пароль, он должен быть хеширован на сервере (может доходить до 10,000 XNUMX итераций). Хеширование на стороне клиента имеет лишь незначительные преимущества; Злоумышленник «человек посередине» (MITM) может просто получить хэш и отправить его на сервер для входа в систему, как законный пользователь. Это может предотвратить утечку фактического пароля и его повторное использование для взлома других служб, но для безопасности конкретных приложений это малоэффективно, но добавляет сложности. Хеширование на стороне сервера является более мощным, поскольку злоумышленник не знает вашей конфигурации хеширования на сервере, поэтому, даже если все ваши хэши просочились, он все равно не сможет аутентифицировать себя. Это следует рассматривать как обязательное.

Даже если все вышеперечисленные шаги предприняты, важно подготовиться к возможной причине утечки вашей базы данных вместе с хэшами: злоумышленник может затем взломать хэши. Это делается

  1. Хэширование потенциального пароля.
  2. Проверка соответствия хэша паролю в базе данных.

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

Лучшее растяжение ключа Алгоритмы, доступные сегодня для паролей, Аргон2ид ³, который выиграл 2015 Конкурс хэширования паролейи PBKDF2 , рекомендованный NIST. Они используют обычные простые функции хеширования, такие как SHA256, в качестве «бэкэндов», но применяют их тысячи раз и автоматически добавляют соль. Следовательно, не напрямую использовать простые хэш-функции, такие как SHA или MD5, не предназначенные для паролей, и не пытаться создавать свои собственные методы растяжения ключей, это глупая затея.

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

Еще одна обязательная мера предосторожности во время аутентификации — убедиться, что вся транзакция проходит через TLS, что значительно усложняет атаки HTTP MITM, требуя сертификаты.

TLS (Transport Layer Security) является преемником протокола SSL (Secure Socket Layer). Короче говоря, TLS сначала включает процедуру рукопожатия, которая требует от сервера отправки сертификата от доверенного центра, подтверждающего его легитимность. Затем происходит обмен ключами шифрования с использованием Метод Деффи-Хеллмана (генерируются как открытый, так и закрытый ключи). Остальная часть сеанса затем шифруется и расшифровывается с использованием этих ключей.

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

Многофакторная аутентификация

На сегодняшний день лучший способ предотвратить сбои в защите паролей — это рекомендовать или требовать многофакторную аутентификацию (MFA). Это означает использование одного или нескольких других методов для аутентификации пользователя. Это может включать использование электронной почты, SMS, QR-кодов, биометрических сканирований и приложений для аутентификации. Наиболее распространенный способ сделать это — использовать электронную почту или SMS для отправки пользователю OTP, который ему необходимо будет ввести, чтобы получить доступ. Затем злоумышленнику потребуется доступ к электронной почте пользователя, чтобы получить доступ к вашей службе.
Это открывает другие векторы атаки, но для большинства приложений этого должно быть достаточно.

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

  • Смена паролей.
  • Проведение денежных операций.
  • Отключение МФА.
  • Получение доступа администратора.

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

Предотвращение ботов

Один из способов предотвратить автоматические попытки входа в систему, будь то в рамках атаки грубой силы или DOS, — это реализовать тайм-ауты после нескольких неудачных попыток. Это приводит к тому, что атаки методом перебора и атаки по словарю занимают слишком много времени, чтобы их можно было осуществить. Другая возможность состоит в том, чтобы потребовать от пользователя решения капчи при каждом входе в систему или, возможно, после заранее определенного количества неудачных попыток. 

решена reCAPTCHA
рекапчи

Возможно, самым популярным сторонним сервисом капчи является reCAPTCHA от Google, но он некоторая критика для его политики конфиденциальности. reCAPTCHA также эффективно заставляет ваших пользователей принимать соглашение об условиях обслуживания третьей стороны, чтобы использовать ваш сервис, что некоторые считают этически проблематичным. Тем не менее, использование reCAPTCHA, вероятно, является самым простым и одним из самых надежных способов предотвращения спама или ботов с перебором. В Интернете есть и другие решения Captcha, такие как hCaptcha, но как сторонние решения, все они могут страдать от тех же проблем, что и reCAPTCHA.

Сообщения об ошибках

Чтобы злоумышленники не могли определить, является ли имя пользователя действительным или нет, рекомендуется иметь одно неоднозначное сообщение об ошибке, независимо от того, вызвана ли ошибка

  • Пароль был неправильным.
  • Аккаунт не существует.
  • Учетная запись заблокирована, отключена или заблокирована.

Правильное безопасное сообщение об ошибке будет выглядеть примерно так:

"Login failed; Invalid user ID or password."

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

"If that email address is in our database, we will send you an email to reset your password."

И,

"A link to activate your account has been emailed to the address provided."

Соответственно.

Даже если ваши сообщения об ошибках расплывчаты, настойчивый злоумышленник может попытаться сравнить расхождения во времени ответа, чтобы определить, является ли пароль неправильным или учетная запись не существует. Например, этот псевдокод

if (user_exists(username)) {
    String password_hash = hash(password);
    bool valid = lookup_credentials(username, password_hash);
    if (!valid) {
        return Error("Invalid Username or Password!");
    }
} else {
   return Error("Invalid Username or Password!");
}

Вернется быстрее, если пользователь не существует, что может использовать злоумышленник, тогда как этот код

String password_hash = hash(password);
bool valid = lookup_credentials(username, password_hash);
if (!valid) {
   return Error("Invalid Username or Password!");
}

В обоих случаях потребуется примерно одинаковое количество времени.

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

В последние годы в моду вошел метод аутентификации, известный как единый вход. Когда пользователь хочет войти в вашу службу, ему предлагается выбрать доверенного поставщика удостоверений, обычно это мегакорпорация, которая предлагает эту услугу, например Google, Amazon или Facebook. Затем пользователь перенаправляется на веб-сайт поставщика удостоверений и должен войти в систему, используя свою учетную запись. Затем поставщик удостоверений отправляет вашей службе гарантию того, что пользователь авторизован, обычно в форме XML-схемы, которая также предоставляет подробные сведения об удостоверении пользователя. Для этого существует несколько протоколов, но самым популярным на сегодняшний день является OpenID.

Основным преимуществом является простота использования. Пользователь должен поддерживать только одну учетную запись с одним паролем для доступа к множеству различных услуг. Кроме того, если пользователь уже вошел в эту учетную запись, ему не нужно повторно вводить свои учетные данные. Это также позволяет пользователю помнить один пароль для всех своих учетных записей. Еще одним преимуществом для разработчика является снижение необходимости самостоятельно заботиться об авторизации. Вместо этого вы делегируете его какой-либо доверенной третьей стороне, такой как Google.

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

Многие современные веб-сайты часто предлагают как SSO, так и традиционные учетные записи с одной службой, оставляя выбор за пользователем.


¹ Национальный институт стандартов и технологий


² Доступно 143,859 143,859 символов Unicode. Это означает, что существует максимум XNUMX XNUMX8 ≈ 1.83 × 1041 возможные 8 комбинаций символов. Сравните со 128.8 = 7.2 × 1016 комбинации ASCII.

³ ragon2id следует использовать со следующими конфигурациями: 

  • m=37 МБ, t=1, p=1
  • m=15 МБ, t=2, p=1

Где m — минимальный объем памяти, t — количество итераций, а p — степень параллелизма. Они равноценны по безопасности, но первый более прожорлив к памяти, но менее требователен к процессору, и наоборот. Не забудьте использовать Aragon2id вариант.

⁴При хешировании с помощью PBKDF2 количество итераций следует устанавливать на основе используемого внутреннего алгоритма хеширования. Следующие предложения эквивалентны по безопасности:

  • PBKDF2-HMAC-SHA1: 720,000 XNUMX итераций
  • PBKDF2-HMAC-SHA256: 310,000 XNUMX итераций
  • PBKDF2-HMAC-SHA512: 120,000 XNUMX итераций
перейти к содержанию