Пейджер

🌍 Вітаю! 🇧🇾

TL;DR
  • TOCTOU — Time of Check to Time of Use, гонка между проверкой и использованием данных
  • Реальный кейс: админ оценивал 2 кандидатов, за 50 секунд добавился 3-й → ошибка валидации
  • Защита: Optimistic/Pessimistic locking, атомарные операции, UX-обновления страницы
🌍 Вітаю! 🇧🇾

На днях взял тикет, на работе, где пользователь 5 раз подряд прожимал отправку формы и 5 раз получил ошибку. Сидел 7 минут, ретраил, сильно пытался победить форму. 👨‍💻

Осторожно! ⚠️
Дальше скрытая реклама ☝️

Я открыл свой сервис для полуавтоматического исправления проблем, который за 10 минут разобрался и дал отчет с диагностикой, оказалось, это клаccический TOCTOU.

Меня это прям сильно заинтересовало. 😋

🔭 Что такое TOCTOU?

TOCTOU это Time of Check to Time of Use. Гонка между моментом проверки и моментом использования.

🍿 На пальцах: вы заметили что вкусный куличик все еще на своем месте 👌, пошли делать чаёк, вернулись — а ваша любимая семья уже сделала свое дело.

Как итог ваша проверка устарела.

В коде все аналогично: система проверяет состояние данных, а между проверкой и действием, данные меняются.

🪛 Реальный кейс

Есть форма, где нужно оценить ВСЕХ пользователей, которые находятся в определенном состоянии. Бизнеc логика простая: или оцениваем всех, или никого.

1️⃣ Пользователь открывает форму
➡️ Система подтягивает кандидатов в статусе "На оценке" — их 2

2️⃣ Пока администратор заполняет оценки (~5 минут), другой пользователь подвинулся в состояние на оценку.
➡️ В статусе "На оценке" теперь 3

3️⃣ Нажимает "Отправить"
➡️ Сервер: в запросе 2 кандидата, а в базе уже 3 → не совпадает → ошибка

🔖 Тайминги из базы

Ну чтоб не быть голословным, достал данные из логов:

➡️ 04:23 — пользователь B добавлен на оценку
➡️ ~04:25 — администратор открывает форму, видит кандидатов A и B
➡️ 04:31:32 — пользователь C создан
➡️ 04:31:46 — кандидат C попал в статус "На оценке"
➡️ 04:32:36 — отправка формы → ОШИБКА 💥
➡️ 04:33 — 04:39 — ещё 4 попытки, всё та же ошибка (форма все это время открыта с тем же составом пользователей)

50 секунд. Кандидат C залетел в нужный статус за 50 секунд до сабмита.

💡 Важный момент: проблемы из-за этого не произошло, валидация сработала ДО любых сайд-эффектов — ни один пользователь не был оценён частично, данные остались консистентными. Валидация свою работу сделала на 💯

🙌 Где ещё можно встретить TOCTOU?

Это не редкий фрукт, встречается постоянно:

➡️ Проверили наличие товара → пока оформляли заказ, последний купили
➡️ Проверили свободный слот → пока бронировали, кто-то занял
➡️ Проверили баланс → пока списывали, пришла другая транзакция
➡️ Проверили права на файл → пока открывали, файл подменили

Любая проверка, после которой идёт пауза до действия — потенциальный TOCTOU

🛡 Как защищаться?

➡️ Optimistic locking — version/timestamp на записи, при обновлении проверяем что версия не изменилась. Если изменилась — конфликт, повтор
➡️ Pessimistic locking — SELECT FOR UPDATE, блокируем запись на время операции. Надёжно, но медленнее
➡️ Атомарные операции — проверка и действие в одном запросе/транзакции, без зазора между ними
➡️ UX — показать пользователю, что данные изменились и предложить обновить форму

⚠️ В моём случае валидация была абсолютно правильной — она не давала оценить только часть кандидатов. Проблема была в UX: вместо понятного "появились новые кандидаты, обновите страницу" юзер получал непонятную ошибку и ретраил 7 минут 🤪

💬 Делитесь своим мнением в комментариях👇! Если вам понравился пост, не забудьте поставить лайк! 👍

#BUG
Медиа 1
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @ivanchikovitclub Открыть пост в Telegram