fix(security): add rate limiting for OTP endpoints
- Add verifyOtpLimiter: 5 attempts per 15 minutes per email/IP - Add requestOtpLimiter: 3 attempts per 15 minutes per email/IP - Use email as primary key, fallback to IP - Return JSON error messages for rate limit exceeded 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2f25940e0a
commit
a055e1b6f8
@ -2,10 +2,39 @@ const express = require('express');
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
|
const rateLimit = require('express-rate-limit');
|
||||||
const { supabase } = require('../config/supabase');
|
const { supabase } = require('../config/supabase');
|
||||||
const { sendOTPEmail } = require('../services/email');
|
const { sendOTPEmail } = require('../services/email');
|
||||||
const storage = require('../services/storage');
|
const storage = require('../services/storage');
|
||||||
|
|
||||||
|
// Rate limiter for OTP verification: 5 attempts per 15 minutes per email/IP
|
||||||
|
const verifyOtpLimiter = rateLimit({
|
||||||
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||||
|
max: 5,
|
||||||
|
keyGenerator: (req) => {
|
||||||
|
// Use email if provided, otherwise fall back to IP
|
||||||
|
const email = req.body?.email?.toLowerCase()?.trim();
|
||||||
|
return email || req.ip;
|
||||||
|
},
|
||||||
|
message: { error: 'Too many verification attempts. Please try again in 15 minutes.' },
|
||||||
|
standardHeaders: true,
|
||||||
|
legacyHeaders: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rate limiter for OTP request: 3 attempts per 15 minutes per email/IP
|
||||||
|
const requestOtpLimiter = rateLimit({
|
||||||
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||||
|
max: 3,
|
||||||
|
keyGenerator: (req) => {
|
||||||
|
// Use email if provided, otherwise fall back to IP
|
||||||
|
const email = req.body?.email?.toLowerCase()?.trim();
|
||||||
|
return email || req.ip;
|
||||||
|
},
|
||||||
|
message: { error: 'Too many OTP requests. Please try again in 15 minutes.' },
|
||||||
|
standardHeaders: true,
|
||||||
|
legacyHeaders: false,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/auth/check-email
|
* POST /api/auth/check-email
|
||||||
* Проверяет существует ли пользователь с данным email
|
* Проверяет существует ли пользователь с данным email
|
||||||
@ -49,8 +78,9 @@ router.post('/check-email', async (req, res) => {
|
|||||||
* POST /api/auth/request-otp
|
* POST /api/auth/request-otp
|
||||||
* Отправляет OTP код на email
|
* Отправляет OTP код на email
|
||||||
* Если пользователя нет - создаёт нового
|
* Если пользователя нет - создаёт нового
|
||||||
|
* Rate limited: 3 requests per 15 minutes per email/IP
|
||||||
*/
|
*/
|
||||||
router.post('/request-otp', async (req, res) => {
|
router.post('/request-otp', requestOtpLimiter, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { email } = req.body;
|
const { email } = req.body;
|
||||||
|
|
||||||
@ -137,8 +167,9 @@ router.post('/request-otp', async (req, res) => {
|
|||||||
/**
|
/**
|
||||||
* POST /api/auth/verify-otp
|
* POST /api/auth/verify-otp
|
||||||
* Проверяет OTP код и возвращает JWT токен
|
* Проверяет OTP код и возвращает JWT токен
|
||||||
|
* Rate limited: 5 attempts per 15 minutes per email/IP
|
||||||
*/
|
*/
|
||||||
router.post('/verify-otp', async (req, res) => {
|
router.post('/verify-otp', verifyOtpLimiter, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { email, code } = req.body;
|
const { email, code } = req.body;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user