В современном цифровом мире безопасность имеет первостепенное значение, и веб-сайты, предлагающие пользователям регистрацию и вход в систему, должны обеспечивать безопасность данных своих пользователей. В этой статье мы рассмотрим, как реализовать безопасный вход и регистрацию в Node JS.
Введение
Безопасный вход и регистрация относятся к процессу аутентификации пользователей и защиты их данных от несанкционированного доступа. Крайне важно внедрить надежные меры безопасности для защиты личной информации пользователей, включая их учетные данные для входа и другие конфиденциальные данные.
Узел JS
Node JS — это кроссплатформенная серверная среда выполнения с открытым исходным кодом, которая позволяет разработчикам создавать быстрые, масштабируемые и высокопроизводительные приложения. Он построен на основе JavaScript-движка Chrome V8 и использует управляемую событиями неблокирующую модель ввода-вывода, что делает его идеальным для создания приложений реального времени.
Преимущества использования Node JS включают его скорость, масштабируемость и способность обрабатывать большие объемы трафика, что делает его популярным выбором для разработки веб-приложений.
Безопасный вход и регистрация в Node JS
Есть несколько мер, которые разработчики могут предпринять для обеспечения безопасного входа и регистрации в Node JS. Одной из таких мер является использование bcrypt для хеширования паролей. Bcrypt — это функция хеширования паролей, разработанная так, чтобы быть медленной и дорогостоящей в вычислительном отношении, что затрудняет взлом паролей злоумышленниками.
Еще одна мера — внедрить паспорт.js для аутентификации. Passport.js — это промежуточное ПО, которое обеспечивает аутентификацию для приложений Node JS. Он поддерживает различные методы аутентификации, включая локальную аутентификацию, OAuth и OpenID.
Интеграция управления сеансами — еще одна важная мера повышения безопасности. Управление сеансом помогает предотвратить перехват сеанса и обеспечивает аутентификацию пользователей для каждого запроса.
Лучшие практики для безопасного входа и регистрации в Node JS
В дополнение к мерам, упомянутым выше, есть и другие рекомендации, которым разработчики могут следовать, чтобы обеспечить безопасный вход и регистрацию в Node JS. Одной из таких практик является использование HTTPS. HTTPS — это протокол, обеспечивающий безопасную связь через Интернет путем шифрования передаваемых данных.
Внедрение двухфакторной аутентификации — еще одна практика, которая может повысить безопасность. Двухфакторная аутентификация требует, чтобы пользователи предоставили две формы аутентификации, такие как пароль и одноразовый код, отправленный на их телефон, что значительно усложняет злоумышленникам доступ к учетным записям пользователей.
Разработчики также должны применять политики паролей для более надежных паролей, например требовать минимальной длины, сочетания букв верхнего и нижнего регистра и символов.
Для разработки безопасного входа и регистрации API в Node JS мы будем использовать MongoDB.
Начните с установки необходимых пакетов с помощью следующей команды:
npm install mongoose bcryptjs validator express-rate-limit jsonwebtoken cookie-parser
bcryptjs — это библиотека, которая позволяет хэшировать и сравнивать пароли. validator — это библиотека, которая позволяет проверять и очищать строки. express-rate-limit — это промежуточное ПО, облегчающее ограничение скорости запросов. jwt — это библиотека, которая упрощает создание и проверку веб-токенов JSON.
Создайте модель мангуста для коллекции User
const mongoose = require('mongoose'); const bcrypt = require('bcryptjs'); const validator = require('validator'); const jwt = require('jsonwebtoken'); const rateLimit = require('express-rate-limit'); const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true, lowercase: true, trim: true, validate: [validator.isEmail, 'Please provide a valid email address'] }, password: { type: String, required: true, minlength: [8, 'Password must be at least 8 characters long'], maxlength: [128, 'Password must be less than 128 characters long'] }, loginCount: { type: Number, default: 0 } },{ timestamps: true }); // Hash password before saving to database userSchema.pre('save', async function() { const user = this; if (!user.isModified('password')) { return; } const salt = await bcrypt.genSalt(10); user.password = await bcrypt.hash(user.password, salt); }); // Compare password with hashed password in database userSchema.methods.comparePassword = async function(password) { return await bcrypt.compare(password, this.password); }; // Increment login count when user logs in userSchema.methods.incrementLoginCount = async function() { this.loginCount += 1; return await this.save(); }; // Generate a JWT token userSchema.methods.generateAuthToken = function () { const token = jwt.sign({ _id: this._id }, process.env.JWT_SECRET, { expiresIn: '1d' }); return token; }; userSchema.statics.findByToken = async function (token) { try { const decoded = jwt.verify(token, process.env.JWT_SECRET); return await this.findOne({ _id: decoded._id }); } catch (err) { throw new Error(`Error verifying token: ${err.message}`); } }; const User = mongoose.model('User', userSchema); module.exports = User; // Separate module for password validation module.exports.validatePassword = function(password) { const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_\-+={}[\]\\|:;'<>,.?/])[a-zA-Z\d!@#$%^&*()_\-+={}[\]\\|:;'<>,.?/]{8,}$/; return regex.test(password); }; // Separate module for rate limiting module.exports.loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // limit each IP to 5 requests per windowMs message: 'Too many login attempts from this IP, please try again later' });
Модель пользователя включает свойство электронной почты, которое является обязательным, уникальным и подтверждено как электронная почта с помощью библиотеки проверки. Свойство пароля является обязательным и проверяется с помощью регулярного выражения, чтобы убедиться, что оно соответствует определенным критериям, прежде чем оно будет хешировано с помощью bcrypt и сохранено в базе данных. Кроме того, модель включает свойство loginCount со значением по умолчанию, равным 0.
Есть также несколько методов, включенных в пользовательскую модель. Метод comparePassword сравнивает заданный пароль с хешированным паролем, хранящимся в базе данных, с помощью bcrypt. Метод incrementLoginCount увеличивает количество входов пользователя в систему и сохраняет пользователя в базе данных. Метод generateAuthToken создает для пользователя веб-маркер JSON (JWT). Наконец, метод findByToken — это статический метод, который принимает JWT в качестве аргумента, проверяет его с помощью переменной среды JWT_SECRET и возвращает пользователя, связанного с декодированным токеном.
Создайте маршрут входа и контроллер с помощью следующего кода:
login.controller.js
const LoginController = async (req, res) => { // User authentication logic } module.exports = LoginController;
попытки.middleware.js
const rateLimit = require("express-rate-limit"); const ApiRateLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 5, // 5 requests message: "Too many attempts, please try again later.", }); module.exports = ApiRateLimiter;
user.router.js
const express = require("express"); const LoginController = require("../controllers/login.controller"); const ApiRateLimiter = require("../middleware/attempts.middleware"); const router = express.Router(); router.post("/login", ApiRateLimiter, LoginController); module.exports = router;
LoginController
и ApiRateLimiter
были перемещены в отдельные файлы и импортированы в файл user.router.js
. Этот подход следует принципу разделения интересов. Кроме того, мы также следовали принципу инверсии зависимостей, импортируя LoginController
и ApiRateLimiter
вместо их встроенного определения. Новый код также является модульным и его легче тестировать.
exports.login = async (req, res) => { try { const { username, password } = req.body; const user = await User.findOne({ username }); if (!user) { return res.status(401).json({ message: 'Invalid username or password' }); } const isMatch = await user.comparePassword(password); if (!isMatch) { return res.status(401).json({ message: 'Invalid username or password' }); } const token = user.generateAuthToken(); await user.incrementLoginCount(); res.cookie('token', token, { httpOnly: true, sameSite: 'strict', secure: false }); res.json({ message: 'Login successful', status: 1 }); } catch (error) { console.error(error); res.status(500).json({ message: 'Server error' }); } }
Создайте промежуточное ПО, которое может идентифицировать пользователя, делающего запрос, на основе его токена и выполнять операции, специфичные для этого пользователя.
const VerifyToken = async (req, res, next) => { try { const token = req.cookies.token; const user = await User.findByToken(token); if (!user) { throw new Error("Unauthorized"); } req.user = user; next(); } catch (err) { res.status(401).json({ message: err.message }); } }; module.exports = VerifyToken; router.get("/profile", VerifyToken, Profile)
Заключение
В заключение, безопасный вход и регистрация в Node JS имеют решающее значение для защиты личной информации пользователей и предотвращения несанкционированного доступа. Применяя такие меры, как bcrypt для хеширования паролей, внедряя password.js для аутентификации, интегрируя управление сеансами и следуя передовым методам, таким как использование HTTPS, внедрение двухфакторной аутентификации и применение политик паролей, разработчики могут гарантировать, что данные их пользователей безопасный.