Аутентификация — это вышибала на входе в ваше приложение. Каждый раз, когда кто-то регистрируется или входит в систему, ваша система должна решить, действительно ли этот человек тот, за кого себя выдает. Ошибитесь вы — и это будет не просто отладка неудачного входа. Вы рискуете тем, что реальные данные пользователей просто вынесут через дверь. Для правильной реализации этого процесса требуются два надежных инструмента: Bcrypt для защиты паролей при хранении и JSON Web Tokens для проверки личности во время перемещения пользователя по приложению.
Почему хранение в открытом виде — это провал
Если вы вынесете из этой статьи только одно правило, пусть это будет оно: никогда не храните пароли в открытом виде в вашей базе данных. Неважно, находится ли ваша база данных за брандмауэром или доверяете ли вы каждому инженеру в команде. Записывать пароли в таблицы в их исходном виде — все равно что оставлять ключи от дома под приветственным ковриком. В тот момент, когда кто-то получает доступ к этой базе данных — через неправильно настроенный API, утечку резервной копии или инъекционную атаку — все учетные данные мгновенно оказываются под угрозой.
Ущерб умножается на то, что люди используют одни и те же пароли повторно. Одна единственная утечка может скомпрометировать не только ваше приложение, но и электронную почту, банковские и социальные аккаунты пользователя. Вот почему мы хешируем пароли. Хеширование преобразует пароль в запутанную строку, которая не имеет явного сходства с оригиналом. Этот процесс является односторонним и необратимым. Вы не можете вылить «математическую кислоту» на хеш, чтобы растворить его обратно в пароль, который его создал.
Хеширование паролей с помощью Bcrypt
Bcrypt — это функция хеширования, созданная специально для паролей. Она берет обычную строку, пропускает ее через шифр Blowfish и выдает результат, который выглядит примерно так: $2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy. Этот префикс указывает вам алгоритм и фактор стоимости (cost factor). Длинный хвост — это комбинация соли и самого хеша.
Соль — это случайные данные, смешиваемые с паролем перед началом хеширования. Поскольку соль уникальна для каждого пользователя, два человека, выбравшие «password123», в итоге получат совершенно разные хеши в вашей базе данных. Это незначительное различие побеждает радужные таблицы (rainbow tables) — предварительно вычисленные словари хешей для распространенных паролей, — потому что злоумышленникам пришлось бы заново генерировать всю таблицу для каждой уникальной соли.
Bcrypt также намеренно работает медленно. Современное оборудование может подбирать миллиарды хешей в секунду с помощью быстрых алгоритмов, таких как SHA-256. Bcrypt же «тянет кота за хвост». Он запускает процесс хеширования многократно, управляемый фактором стоимости, который вы можете увеличивать по мере того, как компьютеры становятся быстрее. Эта медлительность наказывает любого, кто пытается взломать украденную базу данных методом брутфорса. Законный пользователь не заметит лишних двухсот миллисекунд при входе в систему. А вот злоумышленник, пытающийся проверить миллионы вариантов, — безусловно, заметит.
Как работают JSON Web Tokens
В то время как Bcrypt охраняет входную дверь, JWT выдает пропуск в коридор. JSON Web Token — это компактная, безопасная для URL строка, которая доказывает, что пользователь уже прошел аутентификацию. Думайте об этом как о цифровом удостоверении личности, которое выдает сервер, а клиент носит с собой.
JWT состоит из трех сегментов, разделенных точками: заголовка (header), полезной нагрузки (payload) и подписи (signature). Заголовок определяет тип токена и алгоритм подписи. Полезная нагрузка содержит claims — утверждения о пользователе и самом токене, такие как ID пользователя, имя пользователя и временную метку истечения срока действия. Подпись является криптографической печатью. Сервер создает ее путем кодирования заголовка и полезной нагрузки, а затем пропускает их через секретный ключ. Если кто-то попытается подделать полезную нагрузку, подпись перестанет совпадать, и сервер немедленно отклонит токен.
