Я разрабатываю функционал авторизации и регистрации по номеру телефона и столкнулся с некоторыми вопросами. У меня есть два URL-адреса: <br/> /api/request — это POST-запрос для отправки кода, который принимает только номер телефона. Я выполняю валидацию номера и ограничиваю количество отправок кодов. <br/> Второй URL — /api/confirm — это POST-запрос для проверки кода. И вот тут у меня возникли сложности: какие проверки, помимо проверки самого кода, необходимо реализовать? Моя текущая концепция заключается в следующем: я принимаю номер (который уже известен) и код от пользователя, после чего просто проверяю сам код. Кроме этого, я подумываю об ограничении на количество попыток ввести код, чтобы избежать спама. <br/> <br/> На практике, мне кажется, что реализация для обоих URL не совсем полноценная. Было бы здорово увидеть примеры реализации или описания того, как лучше обрабатывать и проверять эти запросы. <br/> <br/> Я также заметил, что на некоторых сайтах с регистрацией по номеру телефона используются токены, которые создаются при входе на сайт. Можешь подробнее рассказать об этом? <br/> <br/> Вдобавок, вот мой код: <br/> <pre><code class="javascript">const { parsePhoneNumberFromString } = require('libphonenumber-js');
const isValidPhoneNumber = (phone, country) => {
const parsePhoneNumber = parsePhoneNumberFromString(phone, country);
if (!parsePhoneNumber || !parsePhoneNumber.isValid()) return null;
return parsePhoneNumber;
}
exports.requestController = (req, res) => {
const { phone } = req.body;
const formattedNumber = isValidPhoneNumber(phone);
if (!phone || !formattedNumber) {
return res.status(400).json({
message: 'Incorrect number'
})
}
return res.status(200).json(formattedNumber.formatInternational())
}
exports.confirmController = (req, res) => {
const { phone, code } = req.body;
Регистрация и авторизация по номеру телефона включает в себя несколько важных этапов и проверок для обеспечения безопасности и удобства пользователей. Давайте рассмотрим, как можно улучшить вашу реализацию для методов `request` и `confirm`, а также обсудим использование токенов.
### 1. Запрос кода (`/api/request`)
При обработке запроса для отправки кода можно реализовать следующие проверки и логики:
- **Валидация номера телефона**: Вы уже это делаете с помощью `isValidPhoneNumber`. Это хорошо.
- **Ограничение на количество запросов**: Введите лимит на количество запросов, который может быть выполнен для одного номера телефона в единицу времени (например, 5 запросов за 10 минут).
- **Хранение состояния**: Сохраняйте состояние последнего отправленного кода, чтобы избежать отправки одного и того же кода несколько раз и обеспечить актуальность кода, например, он должен действовать определенное время (например, 5 минут).
- **Отправка кода**: После успешной валидации отправьте смс с кодом на номер телефона.
### Пример кода для `request`:
```javascript
let requestCounts = {};
exports.requestController = async (req, res) => {
const { phone } = req.body;
const formattedNumber = isValidPhoneNumber(phone);
if (!formattedNumber) {
return res.status(400).json({ message: 'Invalid phone number' });
}
const currentTime = new Date().getTime();
if (!requestCounts[phone]) {
requestCounts[phone] = { count: 0, lastRequestTime: 0 };
}
if (requestCounts[phone].count >= 5 && (currentTime - requestCounts[phone].lastRequestTime < 600000)) {
return res.status(429).json({ message: 'Too many requests. Try again later.' });
}
const code = generateCode(); // Функция для генерации кода
await sendSms(formattedNumber.formatInternational(), code); // Функция отправки SMS
// Обновление состояния
requestCounts[phone].count++;
requestCounts[phone].lastRequestTime = currentTime;
// Сохраните код в базе данных или другой storage для последующей проверки
saveCodeToStorage(phone, code);
return res.status(200).json({ message: 'Code sent successfully' });
};
```
### 2. Подтверждение кода (`/api/confirm`)
При обработке запроса на подтверждение кода, реализация может включать:
- **Проверка кода**: Сравните код, введённый пользователем, с тем, который хранится для данного номера телефона.
- **Проверка срока действия кода**: Убедитесь, что код ещё действителен (не просрочен).
- **Ограничение на количество попыток**: Ограничьте количество попыток ввода кода (например, 5 попыток).
- **Удаление кода после успешной проверки**: Удалите код из базы данных после успешного подтверждения, чтобы предотвратить повторное использование.
### Пример кода для `confirm`:
```javascript
let confirmAttempts = {};
exports.confirmController = async (req, res) => {
const { phone, code } = req.body;
if (!isValidPhoneNumber(phone)) {
return res.status(400).json({ message: 'Invalid phone number' });
}
const storedCode = await getCodeFromStorage(phone); // Получение кода из базы данных
const currentTime = new Date().getTime();
// Проверка на количество попыток
confirmAttempts[phone] = confirmAttempts[phone] || { attempts: 0, firstAttemptTime: currentTime };
if (confirmAttempts[phone].attempts >= 5 && (currentTime - confirmAttempts[phone].firstAttemptTime < 600000)) {
return res.status(429).json({ message: 'Too many attempts. Try again later.' });
}
if (code !== storedCode || !isCodeValid(storedCode)) {
confirmAttempts[phone].attempts++;
return res.status(400).json({ message: 'Invalid or expired code' });
}
// Код подтвержден, сбросьте попытки
confirmAttempts[phone].attempts = 0;
delete confirmAttempts[phone]; // Удалите информацию о попытках
// Реализуйте логику создания токена для авторизации пользователя
const token = createToken(phone); // Функция для создания токена
return res.status(
Первый запрос = принимаем на сервере номер телефона, генерируем токен (случайная строка длиной, предположим, 64 символа - цифры, буквы большие и маленькие), отправляем его на клиент. Генерируем код доступа, отправляем его смской на телефон. В зависимости от логики можем и не отправлять (если допустим у нас метод для логина а такого юзера еще нет (он еще не зарегистрирован)).
Второй запрос = отправляем с клиента токен (тот 64 символьный полученный от сервера) и строку с кодом из смс. Проверяем на сервере токен и код из смс, если все ок - пускаем в аккаунт.
Примечания:
1) токены и сами попытки входа должны жить определенное количество времени, предположим 5 минут.
2) попытки ввода кода (неправильные вводы) должны быть ограничены разумным числом (ну допустим 5 попыток)
3) если можно то лучше код сделать длиннее - хотя бы 6 цифр, а лучше 8 и более.
4) попытки входа в аккаунт можно ограничить, но тогда будет можно абузить эту "фичу" и блокировать вход чувакам, тут выбираем меньшее из зол исходя из бизнес требований
5) можно экономить на смсках и доставлять код в последних цифрах номера / голосовой озвучкой, отправлять в вк, ватсап, телеграм, вайбер
500 айкью примечания для кое какой защиты от слива бюджета:
1) можно юзать капчу (можно не всегда а когда начинается аномалия по отправке кодов - всплеск количества отправок)
2) как уже и говорил разделение входа и регистрации
3) ставим бот защиту от какого нибудь сервиса по защите от ддос/бот атак
4) иногда можно не отправить код а отправить клиенту респонс что код отправлен, если клиент вводит код - скорее всего это атака. человек же запросит код повторно (потому что он тупо ему не пришел)
5) иногда можно отправить код не сразу а через предположим, 30 секунд - если ввели код раньше - значит что-то не так