Сессия и безопасность
Где держать токен
Токен доступа — это право действовать от имени человека. Он не должен попадать в JavaScript: любой сторонний скрипт на странице, любое расширение браузера и любая XSS-уязвимость немедленно превращаются в кражу доступа.
Рабочая схема:
- код обменивает сервер, а не браузер;
- полученный токен сервер кладёт в куку с флагами
HttpOnly,SecureиSameSite=Lax; - браузер к API напрямую не ходит — запросы идут через ваш сервер, который подставляет токен.
Set-Cookie: sid=<токен>; Path=/; HttpOnly; SameSite=Lax; Secure; Max-Age=43200
Срок жизни сессии выбирает сервис. Удобный вариант — 12 часов со скользящим продлением: пока человек работает, сессия продлевается, а забытая на чужом компьютере закрывается сама.
Если интерфейсу нужно показать, что сессия скоро истечёт, кладите рядом вторую куку без HttpOnly —
с одной лишь отметкой времени. Токен при этом остаётся недоступным для скриптов.
Правило «токен не отдают в браузер» общее для всех токенов Инвойсбокс — где им место и где нет, разобрано в безопасности работы с API. Оттуда же берите порядок действий, если токен всё-таки утёк: для токена пользователя он тот же, только вместо смены ключа в кабинете — завершение сессии и отзыв доступа приложению.
Срок жизни и ротация из общих правил относятся к токену интеграции: у него нет владельца-человека, и он живёт месяцами. Сессия пользователя короткая по замыслу, продлевать её ротацией не нужно — истёкшую сессию заменяет новый вход.
Зачем state и PKCE
| Что | От чего защищает |
|---|---|
state | подмена возврата: без сверки злоумышленник может привести пользователя по своей ссылке с чужим кодом |
code_verifier (PKCE) | перехват кода: код без исходной строки не обменивается на токен |
зарегистрированный redirect_uri | угон кода на чужой адрес |
Все три проверки обязательны. state и code_verifier держите в sessionStorage — они нужны ровно до
возврата и не должны жить дольше вкладки. После обмена удаляйте оба.
Требования к адресу возврата
- Адрес присылается в службу поддержки вместе с заявкой на идентификатор приложения. Незарегистрированный адрес не сработает.
- Боевой адрес — только
https. Для разработки запросите отдельный адрес и отдельный идентификатор приложения, чтобы боевой не пришлось отдавать на локальную машину. - Адрес в запросе авторизации и в обмене кода должен совпадать посимвольно, включая завершающий слэш.
- Не ведите возврат на страницу, которая сама по себе перенаправляет пользователя дальше по адресу из параметра: так открывается дыра в чужой сайт. Куда вернуть человека после входа, храните у себя — и принимайте только внутренние пути.
Ошибки при входе
| Что произошло | Что видно | Что делать |
|---|---|---|
redirect_uri не зарегистрирован или не совпал | возврат не происходит, Инвойсбокс ID показывает ошибку | сверить адрес с тем, что зарегистрирован, вплоть до слэша |
state не совпал | ваша страница возврата не должна продолжать вход | начать вход заново; повторный переход по старой ссылке — нормальная причина |
| код уже использован | обмен отвечает ошибкой | код одноразовый: повторный обмен не делают, нужен новый вход |
| токен не принят | 200 с userId: null | считать, что входа нет: очистить куки и предложить войти снова |
| срок токена истёк | обмен или вызов API отвечает отказом | это не ошибка входа: обновите токен по refresh_token, а вход начинайте заново только если и он не подошёл |
| Инвойсбокс ID недоступен | обмен не завершился | показать человеку, что вход временно недоступен, и не создавать пустую сессию |
Читайте также
- Подключение
- Справочник запросов
- Безопасность работы с API — общие правила для токена интеграции