Поскольку популярность Node.js продолжает расти, становится все более важным обеспечить безопасность API, созданных с использованием этой платформы. Два эффективных способа сделать это — использовать веб-токены JSON (JWT) для аутентификации и ограничения скорости для предотвращения атак методом грубой силы и других вредоносных действий.
В этой статье мы покажем вам, как защитить API Node.js с помощью аутентификации на основе JWT и ограничения скорости. Реализуя эти два метода вместе, вы можете значительно повысить безопасность своего API и защитить данные своих пользователей.
Что такое веб-токены JSON?
Веб-токены JSON — это стандарт для безопасного представления претензий между двумя сторонами. JWT состоят из трех частей: заголовка, полезной нагрузки и подписи. Заголовок и полезная нагрузка представляют собой строки JSON в кодировке Base64Url, а подпись используется для проверки целостности токена.
JWT обычно используются для аутентификации в веб-приложениях. Как только пользователь входит в систему, ему выдается JWT и отправляется обратно клиенту. Затем клиент включает этот токен в последующие запросы к серверу. Затем сервер может декодировать токен и проверить его подпись, чтобы убедиться, что он не был подделан. Если токен действителен, сервер может извлечь информацию из полезной нагрузки, чтобы идентифицировать пользователя и авторизовать его запрос.
Как реализовать аутентификацию на основе JWT в Node.js
Чтобы реализовать аутентификацию на основе JWT в Node.js, вам потребуется установить библиотеку jsonwebtoken
. Эта библиотека предоставляет функции для создания и проверки JWT. Вот пример того, как создать JWT:
const jwt = require('jsonwebtoken'); const payload = { user: 'johndoe' }; const secret = 'mysecret'; const token = jwt.sign(payload, secret, { expiresIn: '1h' }); console.log(token);
В этом примере мы создаем JWT с полезной нагрузкой, содержащей свойство user
, для которого установлено значение johndoe
. Мы используем секретный ключ mysecret
для подписи токена и устанавливаем срок действия 1 час, используя опцию expiresIn
.
Чтобы проверить JWT, вы можете использовать функцию verify
библиотеки jsonwebtoken
:
const jwt = require('jsonwebtoken'); const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obmRvZSJ9.-MQPfE60laMNGxyZsUbIb3AsA0y0FVmqr2k7_UimN_g'; const secret = 'mysecret'; jwt.verify(token, secret, (err, decoded) => { if (err) { console.error(err); } else { console.log(decoded); } });
В этом примере мы проверяем JWT с помощью функции verify
. Мы передаем JWT и секретный ключ, используемый для подписи токена. Если токен действителен, декодированные полезные данные будут зарегистрированы в консоли.
Что такое ограничение скорости?
Ограничение скорости — это метод, используемый для предотвращения злоупотребления API, путем ограничения количества запросов, которые могут быть сделаны в течение заданного периода времени. Это может помочь предотвратить атаки грубой силы, DDoS-атаки и другие формы злонамеренной деятельности.
Существует много стратегий ограничения скорости, но один из распространенных подходов заключается в ограничении количества запросов на IP-адрес за период времени. Например, вы можете ограничить каждый IP-адрес 100 запросами в час.
Как реализовать ограничение скорости в Node.js
Чтобы реализовать ограничение скорости в вашем приложении NodeJS, вы можете использовать такой пакет, как «express-rate-limit». Этот пакет предоставляет промежуточное программное обеспечение, которое можно использовать для ограничения количества запросов с определенного IP-адреса в течение определенного периода времени. Вот пример:
const rateLimit = require("express-rate-limit"); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100 // limit each IP to 100 requests per windowMs }); // apply to all requests app.use(limiter);
В приведенном выше коде мы создаем ограничитель скорости, который разрешает максимум 100 запросов на IP-адрес в течение 15-минутного окна. Затем это промежуточное ПО применяется ко всем запросам с использованием app.use(limiter)
.
Теперь давайте интегрируем этот ограничитель скорости с нашей системой аутентификации JWT. Мы изменим наше промежуточное ПО jwtVerify
, чтобы также проверять ограничение скорости для входящего запроса:
const jwt = require("jsonwebtoken"); const rateLimit = require("express-rate-limit"); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100 // limit each IP to 100 requests per windowMs }); function jwtVerify(req, res, next) { // Check if the request has a JWT token in the Authorization header const token = req.headers.authorization; if (!token) { return res.status(401).json({ message: "Authorization header not found" }); } // Verify the JWT token and extract the payload jwt.verify(token, secretKey, (err, payload) => { if (err) { return res.status(401).json({ message: "Invalid token" }); } // Check the rate limit for the incoming request const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress; limiter.get(ip, (err, limit) => { if (err) { return next(err); } // Check if the request has exceeded the rate limit if (limit.remaining === 0) { return res.status(429).json({ message: "Too many requests" }); } // Update the rate limit for the incoming request res.set("X-RateLimit-Limit", limit.total); res.set("X-RateLimit-Remaining", limit.remaining - 1); // Save the JWT payload in the request object for future use req.user = payload; // Call the next middleware in the chain next(); }); }); } // Apply the rate limiter and JWT middleware to all API endpoints app.use(limiter); app.use("/api", jwtVerify);
В приведенном выше коде мы изменили наше промежуточное ПО jwtVerify
, чтобы также проверять ограничение скорости для входящего запроса с использованием метода limiter.get()
. Если запрос превысил ограничение скорости, мы возвращаем ответ 429 с сообщением «Слишком много запросов». В противном случае мы обновляем заголовки ограничения скорости в ответе и сохраняем полезную нагрузку JWT в объекте запроса для использования в будущем.
Наконец, мы применяем ограничитель скорости и промежуточное ПО JWT ко всем конечным точкам API, используя app.use()
. Теперь наш NodeJS API защищен как аутентификацией JWT, так и ограничением скорости, чтобы предотвратить злоупотребления и обеспечить его доступность для законных пользователей.