Глоссарий

Что такое TOCTOU: когда состояние меняется между проверкой и использованием

TOCTOU (time-of-check to time-of-use) — это состояние гонки, при котором состояние меняется после проверки. Как это работает и как защититься: объединить проверку и использование в одном шаге.

Опубликовано 2026-11-15 Обновлено 2026-11-15 5 мин чтения
На этой странице

TOCTOU (time-of-check to time-of-use) — это проблема, при которой состояние объекта меняется между моментом его проверки и моментом использования. На этой странице объясняется, как это работает и как это предотвратить (без шагов атаки).

Что такое TOCTOU

Программы часто работают по принципу «проверь, и если всё в порядке, используй»: например, «проверить, что в файл можно писать, затем открыть и записать». Но между проверкой и использованием есть небольшой промежуток времени. Если в этом промежутке другая программа или запрос меняет цель, результат проверки перестаёт быть верным.

В CWE-367 от MITRE это описано как продукт, который проверяет состояние ресурса перед использованием, причём состояние может измениться между проверкой и использованием так, что проверка теряет силу. CWE (Common Weakness Enumeration) — общий каталог слабостей, лежащих в основе уязвимостей. TOCTOU — это разновидность состояния гонки, когда результат зависит от времени выполнения параллельных процессов.

Почему это происходит

1. Проверка: можно ли писать в этот файл? → OK
2. Промежуток: другой процесс заменяет то, на что указывает это имя
↓ результат проверки больше не соответствует действительности
3. Использование: программа пишет в цель, которую она никогда не проверяла
Когда проверка и использование выполняются отдельными шагами, цель может быть подменена между ними, и результат проверки устаревает.

По данным CWE-367, последствия могут включать доступ к ресурсам, которые должны быть недоступны, изменение ресурсов нежелательным образом и отсутствие записей в журналах. Промежуток может быть коротким, но в системах, которые выполняют много задач одновременно, он повторяется регулярно, а не только по случайности.

Где это проявляется

МестоПроверкаИспользованиеЧто идёт не так
Работа с файламиПроверка существования или правОткрытие или записьФайл подменяют после проверки
Остаток товара или баланс в веб-приложенииSELECT текущего остаткаUPDATE для его уменьшенияДва параллельных запроса оба проходят проверку и превышают лимит
Платежи и регистрацияЕщё не обработано?Выполнение действияДвойная отправка выполняет его дважды
Загрузка файловПроверка содержимогоСохранение или публикацияСодержимое меняется после проверки

Про проверку загрузок см. также уязвимости при загрузке файлов.

Защита: не отделяйте проверку от использования

1

Не проверяйте перед использованием

Самый базовый совет CWE-367 — не выполнять проверку перед использованием. Работайте с ресурсом напрямую и обрабатывайте ошибку, если операция не удалась. Это устраняет сам промежуток.

2

Используйте файловые дескрипторы, а не пути

Сначала откройте файл, затем проверяйте состояние и записывайте данные через открытый файловый дескриптор. Повторный поиск по имени пути может каждый раз указывать на другой объект. Помогают также флаги, например O_NOFOLLOW (не переходить по символическим ссылкам), и вызовы, например openat (открытие относительно каталога); что доступно, зависит от ОС.

3

Для баз данных используйте условные обновления и транзакции

Вместо схемы «SELECT для проверки, затем UPDATE» используйте один UPDATE, включающий условие (например, уменьшать счётчик только тогда, когда он равен 1 или больше). Если операций несколько, используйте транзакцию с подходящим уровнем изоляции и блокировками строк.

4

Берите блокировку до проверки

Если вы используете блокировки, берите их до проверки, как говорит CWE-367. Блокировка после проверки не гарантирует, что проверенный объект — это тот объект, который вы используете.

5

Предотвращайте двойное выполнение с помощью ключей идемпотентности

Для платежей и регистрации присваивайте каждому запросу уникальный ключ (ключ идемпотентности) и выполняйте действие только один раз для каждого ключа.

Как проверить собственный код

Делайте это в коде, который вы разрабатываете или поддерживаете.

  1. Найдите места, где код проверки и код использования — это отдельные вызовы (проверка существования, затем открытие; SELECT, затем UPDATE)
  2. Для каждого места определите, можно ли убрать проверку и сделать этот шаг одной операцией
  3. Напишите тест, который отправляет один и тот же запрос несколько раз одновременно, и убедитесь, что применён только один
  4. Никогда не пробуйте это на чужом сервисе; используйте собственное окружение

Позиция этого сайта: поместите проверку внутрь той же операции, что и использование

TOCTOU — это не «кто-то забыл проверку». Проверка существует, просто она отделена от использования. Добавление ещё одного кода проверки эту проблему не решает. Решение — поместить проверку внутрь той же атомарной операции, что и использование, а не добавлять её как лишний шаг. Изучение вместе с IDOR помогает на ревью: оба относятся к ошибкам типа «проверка есть, но она не выполняет свою задачу».

Источники (первоисточники)

  • MITRE CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition — cwe.mitre.org (определение, последствия, меры защиты)
  • Конкретные приёмы (O_NOFOLLOW, openat, ключи идемпотентности, транзакции) описаны как общая практика реализации; доступность зависит от ОС и базы данных, поэтому проверяйте официальную документацию каждого продукта

Читайте дальше

Классификация

CWE классифицирует типы слабостей, из-за которых возникают уязвимости; MITRE ATT&CK классифицирует техники атакующих. Обе системы ведёт MITRE, и они широко используются для разметки уязвимостей и правил обнаружения.

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

FAQ

QЧто означает TOCTOU?
A

Это сокращение от time-of-check to time-of-use (время проверки — время использования). Состояние ресурса меняется между моментом, когда его проверили, и моментом, когда его использовали. В CWE-367 от MITRE это описано как продукт, который проверяет состояние ресурса перед использованием, причём состояние может измениться так, что проверка теряет силу. Это разновидность состояния гонки.

QГде возникает TOCTOU?
A

Классическое место — работа с файлами: программа проверяет, существует ли файл или можно ли в него писать, затем открывает его отдельным вызовом, и файл может быть подменён между этими действиями. Такое также случается в веб-приложениях и базах данных, например при сценарии «проверить остаток, затем подтвердить заказ» или «проверить баланс, затем списать», если проверка и обновление выполняются отдельными шагами.

QКакая главная защита?
A

Объединить проверку и использование в одну атомарную операцию. CWE-367 говорит, что самый базовый совет — не выполнять проверку перед использованием. Для файлов сначала откройте файл, затем проверяйте и работайте с открытым файловым дескриптором. Для баз данных используйте условное обновление или транзакцию с блокировкой.

QДелает ли блокировка код безопасным всегда?
A

Блокировку нужно брать до проверки, а не после. CWE-367 указывает, что блокировка должна происходить до проверки, а не после неё. Блокировка после проверки не гарантирует, что проверенный объект — это тот объект, который вы используете. Кроме того, блокировка не поможет, если её область слишком узкая или другие программы её игнорируют.

QЗатрагивает ли TOCTOU веб-приложения?
A

Да. Примеры: сохранение загруженного файла после его проверки, уменьшение счётчика купонов или остатка товара после чтения, а также обработчики платежей, которые не должны выполняться дважды. Если один и тот же запрос приходит дважды одновременно, оба могут пройти проверку. Сделайте обновление одной условной операцией и используйте ключи идемпотентности, чтобы предотвратить повторное выполнение.

QКак искать TOCTOU в своём коде?
A

Найдите места, где код проверки и код использования находятся в разных строках или вызовах. В работе с файлами это проверка существования или прав, после которой файл открывается по пути. В работе с базой данных это SELECT для проверки, после которого идёт UPDATE. Затем определите, можно ли убрать проверку и сделать одну операцию, и добавьте тесты на параллельные запросы.