Как осуществляется регистрация с использованием номера телефона?

Я разрабатываю функционал авторизации и регистрации по номеру телефона и столкнулся с некоторыми вопросами. У меня есть два 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) =&gt; {
    const parsePhoneNumber = parsePhoneNumberFromString(phone, country);

    if (!parsePhoneNumber || !parsePhoneNumber.isValid()) return null;
    return parsePhoneNumber;
}

exports.requestController = (req, res) =&gt; {
    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) =&gt; {
    const { phone, code } = req.body;
  • 30 марта 2025 г. 11:25
Ответы на вопрос 2
Регистрация и авторизация по номеру телефона включает в себя несколько важных этапов и проверок для обеспечения безопасности и удобства пользователей. Давайте рассмотрим, как можно улучшить вашу реализацию для методов `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 секунд - если ввели код раньше - значит что-то не так
Похожие вопросы