Введение
Защита паролей сайта – это неотъемлемый навык, который должен владеть каждый разработчик. JavaScript
предоставляет опцию для обеспечения безопасного хранения и обработки паролей или других конфиденциальных данных с использованием алгоритмов хэширования, предоставленных модулем BcryptJS
в JavaScript
.
В этом руководстве вы узнаете о BcryptJS
и хэшировании для создания основного сервера express, который будет хранить пароли в виде хэшей в базе данных, а не в виде обычных строк, и извлекать их для аутентификации пароля.
Предварительные требования
Для продолжения этого руководства у вас должна быть следующая настройка.
-
Стабильная версия Node.js, установленная на вашем компьютере с версией 12.x или выше. Вы можете использовать этот учебник DigitalOcean для установки последней версии Node Js на вашем компьютере.
-
Вы должны знать, как писать на JavaScript.
-
_На компьютере должна быть установлена Express JS. Вы можете использовать эту инструкцию, чтобы настроить сервер Express.
-
Наконец, для завершения этого руководства вам понадобится база данных MongoDB Community или Atlas. Вы можете установить её, используя одну из инструкций DigitalOcean по_ установке MongoDB.
Зачем использовать BcryptJS?
Bcrypt – это алгоритм хеширования для создания хешей паролей для их хранения в случае утечки данных. Этот передовой алгоритм хеширования использует соли, что делает его сложным для взлома методами, такими как грубая сила.
BcryptJS – это JavaScript-реализация алгоритма хеширования Bcrypt
, позволяющая использовать хеширование без необходимости заниматься сложными хешированиями. Некоторые из причин, по которым BcryptJS является отличным выбором для защиты паролей, следующие:
-
Безопасность – BcryptJS реализует алгоритм Bcrypt, медленный алгоритм (что в хешировании является хорошим), требующий интенсивной вычислительной мощности. Это делает взлом хеша пароля трудной задачей для злоумышленников, обеспечивая безопасность паролей даже в случае утечки данных._
-
Соление – BcryptJS обрабатывает генерацию случайных солей для паролей для обеспечения безопасности хранения (мы подробнее узнаем о хешах и солях в следующем разделе). Соли делают хеш относительно слабого пароля более сложным, что затрудняет его расшифровку.
-
Простота использования – BcryptJS предоставляет разработчикам JavaScript инструмент для шифрования их паролей без необходимости глубокого понимания хеширования._
На следующем этапе мы кратко узнаем о хешах и соли.
Как работает хеширование?
Прежде чем использовать эти концепции в ваших проектах, вы должны понять, как работают хеширование и соление.
Хеширование
Хеширование – это преобразование обычной строки или текста в строку случайных символов (шифрование). Это позволяет безопасно хранить и/или передавать конфиденциальные данные. Хеширование включает в себя следующие ключевые шаги:
Ввод данных – Во-первых, данные любого типа (бинарные, символьные, десятичные и т. д.) в виде простого текста или строки хранятся.
Хеш-функция – Хеш-функция – это математический алгоритм, который принимает вводные данные и преобразует их в набор символов или хеш-коды. Хеш-функции детерминированы (производят одинаковый вывод для одного и того же ввода) и односторонние функции (это означает, что практически невозможно обратно инженерировать вывод хеш-функций, то есть хеш обратно в его входные данные).
Устойчивость к столкновениям – это означает, что хэш-функция создается с учетом идеи устойчивости к столкновениям, то есть два разных ввода не могут иметь одинаковый вывод (хэш-код).
Аутентификация – хэш-функции детерминированы, производя одинаковый хэш для одного и того же ввода. Таким образом, при аутентификации пароля, хранящегося в виде хэша, общая идея заключается в том, что если пароль для аутентификации совпадает с хэшем, хранящимся в базе данных, пароль верный.
Посолка
Поскольку хэширование существует уже десятилетия, произошли разработки, такие как радужные таблицы, содержащие миллиарды записей данных, содержащих строковые данные и их соответствующие хэши на основе различных алгоритмов хэширования.
Теперь представьте ситуацию, когда пользователь создает учетную запись на вашем веб-сайте с помощью слабого пароля. Таким образом, в случае утечки данных злоумышленник может найти хэши ваших пользователей и найти соответствие хэша для учетной записи пользователя с слабым паролем. Это может оказаться катастрофическим в приложениях с высоким уровнем безопасности. Чтобы предотвратить такое, используются посолы.
Посолка – это дополнительный уровень безопасности, добавляемый к хэшам путем добавления случайной строки символов к хэшу пароля перед его хранением в базе данных. Таким образом, даже если данные утекут в результате нарушения, будет сложно для злоумышленника расшифровать хэш, содержащий посол. Рассмотрим следующий пример:
Как мы можем ясно видеть, пароль, хранящийся с солью, менее вероятно будет взломан из-за детерминированной природы хэшей. Поэтому, если злоумышленник, например, ищет эту строку хэша+пароля в радужной таблице, он не получит фактическую строку пароля, а что-то совершенно другое.
Теперь вы готовы использовать BcryptJS и защитить свои пароли стандартным способом для отрасли.
Установка BcryptJS и других необходимых модулей
Теперь, когда вы знаете о хешировании и соли, все, что остается, это взять ваш компьютер и начать писать код. Структура проекта будет следующей:

Во-первых, мы начнем с создания проекта npm с помощью следующих шагов:
-
Откройте папку и создайте файл,
app.js.
-
Откройте терминальное окно в этой папке и введите команду
После этого вас попросят ввести данные, но вы можете нажать Enter, не вводя никаких данных.
- Затем создайте еще 3 файла, а именно
auth.js
db.js
User.js
- В том же терминальном окне введите следующую команду для установки необходимых пакетов.
Теперь у вас есть полная настроенная среда проекта для следования этому руководству. На следующем этапе вы узнаете, как создать сервер для использования BcryptJS для безопасного хранения и аутентификации паролей с помощью MongoDB.
Настройка сервера с помощью Express JS
Теперь, когда вы настроили структуру проекта, вы можете создать сервер, который использует bcrytjs
для безопасного хранения паролей в виде хэшей и их аутентификации. Мы создадим сервер с помощью следующих правильных шагов.
Шаг 1 – Создание соединения с базой данных MongoDB
Чтобы подключиться к mongoDB
, мы используем версию Community. Чтобы сохранить проект организованным, вы сохраните код для настройки соединения в файле db.js
.
Здесь вы импортируете пакет mongoose
, который предоставляет API для подключения JavaScript к MongoDB.
Также, в этом случае URI соединения предназначен для локальной установки mongoDB, если вы используете облачную базу данных (например, Atlas), вам нужно будет только изменить URI на URI вашей конкретной базы данных.
Информация
URI похож на URL сервера, с тем отличием, что URI может идентифицировать имя и идентичность ресурсов, а также их местоположение в Интернете. В отличие от этого URL является подмножеством URI, способным выполнять только последнее.
Функция connectToMongo
является асинхронной (async), потому что mongoose.connect
возвращает javascript promise. Эта функция предоставит соединение при успешном выполнении. В противном случае она вернет ошибку.
Наконец, мы используем module.exports
, чтобы экспортировать эту функцию при импорте модуля db.js
.
Шаг 2 – Создание схемы пользователя
Вам понадобится базовая схема для создания или аутентификации пользователей в базе данных MongoDB. Если вы не знаете, что такое схема, вы можете использовать отличное руководство DO, чтобы понять и создать схему в MongoDB. Мы будем использовать только два поля для нашей схемы, email
и password
.
Используйте следующий код в вашем модуле User.js
.
Мы создаем два поля в этой схеме, email
и password
. Оба из них являются обязательными полями и имеют тип данных строка. Кроме того, email
является уникальным полем, что означает, что один адрес электронной почты можно использовать только один раз для создания учетной записи на этом сервере.
Наконец, мы экспортируем модель с именем users
. Модель представляет собой схему на стороне базы данных. Вы можете представить себе схему как правило для определения модели, в то время как модель хранится в виде коллекции в базе данных MongoDB
.
Вы можете преобразовать схему в модель, используя функцию model() библиотеки mongoose
.
Шаг 3 – Настройка сервера в файле app.js
После выполнения предыдущих шагов вы успешно создали модель и модуль для подключения к базе данных MongoDB
. Теперь вы узнаете, как настроить сервер. Используйте следующий код в вашем файле app.js
.
Здесь мы импортируем модули express
и db.js
для подключения к MongoDB. Затем мы используем промежуточное ПО express.json()
для обработки JSON-ответов. Маршруты создаются в другом модуле (auth.js
), чтобы код был чистым и организованным. Затем, наконец, мы создаем конечную точку для сервера, чтобы он слушал порт 3300
на localhost. (Вы можете использовать любой порт на ваш выбор)
Шифрование паролей и их сохранение в базе данных MongoDB
До этого момента сервер почти готов, и теперь вы создадите конечные точки для сервера. Мы создадим две конечные точки – signup
и login
. В конечной точке регистрации мы возьмем электронную почту и пароль от нового пользователя и сохраним его с шифрованием для пароля, используя BcryptJS.
В файле auth.js
введите следующий код:
Мы делаем необходимые импорты, а затем настраиваем роутер express для создания конечной точки /signup
. Мы используем метод POST
, чтобы учетные данные не раскрывались в URL-адресе в приложении. После этого мы создаем соль с помощью функции genSalt
пакета scripts
; параметр, переданный в функции genSalt(), содержит длину символа соли. Затем мы используем функцию hash() из BcryptJS, которая принимает обязательный параметр – строку пароля для преобразования в хеш-код, и необязательный аргумент – строку соли. И затем он возвращает хеш, который содержит как пароль
, так и соль
.
После этого мы используем функцию create()
модуля mongoose
для создания документа в нашей базе данных, определенного правилами модели users. Она принимает объект Javascript
, содержащий электронную почту и пароль, но вместо того, чтобы передавать ей обычную строку, мы передаем secPass (хэш пароля + соль) для сохранения в базе данных. Таким образом, мы безопасно сохраняем пароль в базе данных, используя его хэш в сочетании с солью, а не обычную строку. В конечном итоге, мы возвращаем ответ в формате JSON
, содержащий модель пользователя. (Этот метод отправки ответов применяется только на development phase
; в продакшене вы замените его токеном аутентификации или чем-то другим).
Для тестирования этой конечной точки сначала необходимо запустить сервер, что можно сделать, набрав следующую команду в терминале.
Эта команда запустит ваш сервер на localhost и порту 3300
(или на указанном вами порту). Затем вы можете отправить HTTP
-запрос по следующему URL: http://localhost:3300/auth/signup
с следующим телом:
Это приведет к следующему выводу/ответу:
Примечание: Хэш пароля и ID не будут одинаковыми, так как они всегда уникальны.
В следующем разделе вы узнаете, как получить доступ к сохраненному хэшу для пароля и аутентифицировать его с предоставленным при входе в систему/аутентификации паролем.
Доступ к зашифрованному паролю и его использование для аутентификации
До этого вы узнали о BcryptJS,
хэшировании,
солении,
и разработали express сервер
, который создает новых пользователей с паролями, хранящимися как хэши. Теперь вы узнаете, как использовать сохраненный пароль и аутентифицировать пользователя при попытке входа в приложение.
Чтобы добавить метод аутентификации, добавьте следующий маршрут в ваш файл auth.js
после маршрута /signup
:
Здесь мы используем подпуть /auth/login
для выполнения аутентификации при входе для уже существующего пользователя. Подобно конечной точке /auth/signup
, это будет функция async-await, так как BcryptJS возвращает обещания.
Во-первых, мы используем функцию findOne
библиотеки Mongoose, которая используется для поиска документа в коллекции на основе заданного запроса. В этом случае мы ищем пользователя по электронной почте. Если пользователь с предоставленной электронной почтой не существует, то это отправит ответ с кодом состояния 400 для недопустимых учетных данных. (Не рекомендуется указывать, какой параметр неверен при входе в систему, так как злоумышленники могут использовать эту информацию для поиска существующих учетных записей).
Если пользователь с предоставленным адресом электронной почты существует, программа переходит к сравнению паролей. Для этого BcryptJS
предоставляет метод compare()
, который принимает сырую строку в качестве первого аргумента и хеш
(с или без соли
) в качестве второго аргумента. Затем он возвращает Boolean promise
; true
, если пароль совпадает с хешем, и false
, если нет. Затем вы можете добавить простую проверку с использованием оператора if и вернуть успех или ошибку на основе сравнения.
Наконец, вы экспортируете express router
, используя module.exports для начальной точки app.js
, чтобы использовать его для маршрутов.
Чтобы протестировать этот маршрут, вы можете отправить другой HTTP
-запрос по следующему URL-адресу http://localhost:3300/auth/login
со следующим телом:
Этот запрос даст следующий ответ:
В конечном итоге auth.js
будет выглядеть так:
Заключение
Этот учебник создал сервер для объяснения использования BcryptJS для безопасного хранения и доступа к паролям базы данных. Вы можете продолжить, добавив:
-
Реализацию дополнительных маршрутов для других задач, таких как получение учетных данных пользователя, обновление учетных данных пользователя и т. д.
-
Внедрение аутентификационных токенов для отправки в качестве ответов и т.д.
Это начало вашего пути к безопасной работе с паролями; всегда можно усилить безопасность с помощью различных методов и технологий, что позволяет создавать более безопасные и устойчивые приложения.