ADR: Выбор основного языка разработки
- Status: Accepted by Andrei Ganiushkin
andrey@ganyushkin.ru - Date: 2026-06-26
- Authors: Andrei Ganiushkin
andrey@ganyushkin.ru - Related issues: -
Context
Проекту Netgap требуется выбрать основной язык разработки. Приложение имплементирует паттерны logical airgap и должно работать на границе доверенных и недоверенных контуров, где ошибки обработки данных, сетевого взаимодействия, памяти или конкурентного доступа могут становиться критичными дефектами безопасности.
Для проекта важны следующие факторы:
- высокая устойчивость к типовым классам уязвимостей, особенно memory safety ошибкам: use-after-free, double free, buffer overflow, data race и обращение к невалидной памяти;
- предсказуемая производительность без пауз сборщика мусора, так как приложение планируется под realtime нагрузки и должно сохранять малые задержки при интенсивном сетевом и потоковом обмене;
- возможность писать низкоуровневые компоненты, сетевые протоколы, парсеры, криптографические и изоляционные механизмы без перехода на другой язык;
- строгая модель обработки ошибок и состояний, уменьшающая вероятность неявных отказов, некорректного fallback-поведения и silent failure;
- поддержка многопоточности и асинхронной обработки с минимизацией гонок данных на уровне компиляции;
- возможность поставлять компактные бинарные артефакты с контролируемыми зависимостями и без обязательного runtime окружения;
- применимость современных практик secure development lifecycle: dependency audit, fuzzing, static analysis, supply chain контроль, воспроизводимые сборки и автоматическая проверка отсутствия
unsafeв коде проекта.
Для Netgap выбор языка является не только инженерным, но и архитектурным решением безопасности. Язык должен снижать вероятность критичных дефектов в базовой реализации, не ухудшая при этом производительность, задержки и контроль над runtime-поведением.
Decision
В качестве основного языка разработки проекта Netgap выбрать Rust.
Rust должен использоваться для реализации компонентов, связанных с обработкой сетевого трафика, logical airgap паттернами, парсингом входных данных, контролем потоков, политиками безопасности, криптографическими операциями, высоконагруженной realtime-обработкой и системной интеграцией.
Выбор Rust фиксирует следующие архитектурные правила:
- в коде проекта не должно быть
unsafe; это требование должно подтверждаться автоматическими проверками, например запретомunsafe_code, CI-контролем и анализом черезcargo geigerили аналогичные инструменты; unsafeво внешних зависимостях допустим только при соблюдении требований ИБ: минимизация dependency graph, проверка advisory, фиксация версий, анализ происхождения и отдельный review зависимостей, используемых в security-sensitive частях проекта;- если низкоуровневые оптимизации или платформенные интеграции требуют
unsafe, их следует выносить из основного кода в отдельные крейты с явно описанными границами ответственности, инвариантами безопасности, тестами, fuzzing и документированными гарантиями безопасности; - проектировать критичные парсеры, state machine и обработку политик через строгие типы,
enum,Result, явную обработку ошибок и отсутствие неявных исключений; - использовать преимущества Rust ownership и borrow checker для снижения риска memory corruption и data race в многопоточных realtime-сценариях;
- применять zero-cost abstractions и отсутствие garbage collector как основу для предсказуемых задержек;
- ограничивать и контролировать внешние зависимости, особенно в security-sensitive частях проекта;
- для boundary-компонентов и работы с недоверенными входными данными использовать fuzzing, property-based тестирование, dependency audit и статический анализ.
Rust не считается единственной мерой безопасности. Он снижает вероятность целых классов дефектов, но не заменяет threat modeling, secure architecture, defense in depth, code review, тестирование, hardening, мониторинг и управление цепочкой поставки зависимостей.
Considered Alternatives
Alternative 1: Rust
Rust используется как основной язык разработки ядра Netgap и security-sensitive компонентов.
- Pros:
- Обеспечивает memory safety без garbage collector, что особенно важно для security-приложения с realtime требованиями.
- Ownership, borrow checker и строгая система типов уменьшают риск use-after-free, double free, dangling pointer, buffer overflow и data race.
- Отсутствие GC-пауз повышает предсказуемость задержек по сравнению с managed-языками.
- Производительность близка к C/C++ и подходит для интенсивной сетевой обработки, парсеров, очередей, криптографии и системных интеграций.
Result,Option,enumи pattern matching стимулируют явную обработку ошибок и состояний, что важно для корректной реализации security policy.- Экосистема поддерживает инструменты для ИБ-процессов:
cargo audit,cargo deny,cargo geiger, fuzzing, sanitizers, Miri, SBOM, воспроизводимые сборки и проверку отсутствияunsafeв коде проекта.
- Cons:
- Более высокий порог входа и более строгая модель разработки по сравнению с Go, Java, Kotlin или Python.
- Часть экосистемы требует внимательного выбора зависимостей, потому что внешние crate могут содержать
unsafeили иметь слабую поддержку. - Разработка некоторых компонентов может занимать больше времени из-за требований borrow checker и явного моделирования владения данными.
- Reason for selection: Rust дает лучший баланс для Netgap: безопасность памяти и конкурентного доступа на уровне компиляции, высокая производительность, отсутствие GC-пауз и достаточный контроль над низкоуровневым поведением. Для проекта в области информационной безопасности этот баланс важнее, чем максимальная скорость прототипирования.
Alternative 2: C или C++
Проект реализуется на C или C++ для максимального контроля над памятью, системными API и производительностью.
- Pros:
- Максимальный низкоуровневый контроль и зрелая экосистема системной разработки.
- Очень высокая производительность и широкая доступность компиляторов, библиотек и платформенных интеграций.
- Подходит для hard realtime и embedded-сценариев при наличии сильной инженерной дисциплины.
- Cons:
- Высокий риск memory safety уязвимостей, которые особенно опасны для приложения информационной безопасности.
- Безопасность владения памятью, потоков и lifetime в основном обеспечивается дисциплиной команды, code review, sanitizers и дополнительными инструментами, а не компилятором по умолчанию.
- Ошибки парсинга недоверенных данных, переполнения буферов и use-after-free могут приводить к RCE, обходу изоляции или нарушению logical airgap гарантий.
- Для достижения уровня безопасности, сопоставимого с safe Rust, требуется больше ручных практик, ограничений, проверок и времени на аудит.
- Reason for rejection: C и C++ дают высокую производительность, но создают слишком большую поверхность memory safety рисков для базового языка проекта Netgap. Для security-first продукта компиляторная защита Rust предпочтительнее, чем зависимость от дисциплины ручного управления памятью.
Alternative 3: Go
Проект реализуется на Go для быстрого создания сетевых сервисов, конкурентной обработки и простой эксплуатации.
- Pros:
- Простая модель разработки и быстрый цикл сборки.
- Хорошая стандартная библиотека для сетевых приложений, HTTP, TLS, concurrency и tooling.
- Удобная поставка статически собранных бинарных файлов.
- Memory safety выше, чем у C/C++, за счет managed runtime.
- Cons:
- Garbage collector может создавать задержки и менее предсказуемое latency-поведение в realtime-нагрузках.
- Модель ошибок и типов менее выразительна для строгого моделирования security policy и state machine по сравнению с Rust.
- Data race возможны и требуют отдельного обнаружения через race detector и дисциплину разработки.
- Runtime и GC уменьшают контроль над низкоуровневым поведением в критичных участках.
- Reason for rejection: Go хорошо подходит для инфраструктурных сервисов и быстрой разработки, но для Netgap хуже соответствует сочетанию security-first, realtime latency и низкоуровневого контроля. Наличие GC и меньшие компиляторные гарантии конкурентной безопасности делают Rust более подходящим выбором.
Alternative 4: Java или Kotlin
Проект реализуется на JVM для использования зрелой платформы, высокой продуктивности разработки и широкой экосистемы.
- Pros:
- Богатая экосистема библиотек, инструментов наблюдаемости и enterprise-интеграций.
- Высокая продуктивность разработки и зрелые практики тестирования.
- Memory safety в типичных сценариях выше, чем у C/C++.
- JIT может обеспечивать высокую throughput-производительность для долгоживущих сервисов.
- Cons:
- JVM, JIT, warm-up и garbage collector усложняют предсказуемость latency в realtime-сценариях.
- Больший runtime и зависимость от JVM увеличивают эксплуатационную сложность и потенциальную поверхность атаки.
- Низкоуровневый контроль над памятью, системными вызовами и компактностью поставки хуже, чем у Rust.
- Для security appliance или boundary-компонентов JVM может быть избыточной платформой.
- Reason for rejection: Java и Kotlin подходят для бизнес-сервисов и control plane, но хуже подходят как основной язык для ядра security-приложения с logical airgap паттернами и realtime требованиями. Rust обеспечивает более компактную поставку, лучшую предсказуемость задержек и больший контроль над критичными участками.
Alternative 5: Zig
Проект реализуется на Zig как современном системном языке с простым runtime и явным управлением памятью.
- Pros:
- Высокий контроль над памятью, сборкой и системными интеграциями.
- Отсутствие garbage collector и хорошая применимость для низкоуровневых компонентов.
- Более простая языковая модель по сравнению с C++ и потенциально удобная кросс-компиляция.
- Cons:
- Экосистема, tooling и кадровый рынок менее зрелые, чем у Rust.
- Гарантии memory safety слабее, чем у safe Rust, и больше зависят от дисциплины разработки.
- Для security-critical проекта выше риск нехватки проверенных библиотек, практик аудита и долгосрочной поддержки.
- Reason for rejection: Zig перспективен для системной разработки, но на текущем этапе Rust предоставляет более зрелый баланс безопасности, производительности, tooling и экосистемы для проекта Netgap.
Consequences
Positive
- Проект получает основной язык, который снижает вероятность memory corruption и data race уязвимостей в базовой реализации.
- Realtime-компоненты могут работать без GC-пауз и с более предсказуемыми задержками.
- Security-sensitive логика может быть выражена через строгие типы, явные состояния и обязательную обработку ошибок.
- Низкоуровневые компоненты, сетевые протоколы, парсеры и интеграции можно реализовывать без перехода на C/C++ как основной язык.
- Компактные бинарные артефакты упрощают поставку, изоляцию, hardening и эксплуатацию.
- Экосистема Rust позволяет встроить в процесс разработки dependency audit, fuzzing, статический анализ и автоматическое подтверждение отсутствия
unsafeв коде проекта. - Выбор языка хорошо соответствует назначению Netgap как приложения информационной безопасности, реализующего logical airgap паттерны.
Negative
- Скорость разработки на раннем этапе может быть ниже из-за порога входа, borrow checker и необходимости точнее моделировать владение данными.
- Не все библиотеки экосистемы одинаково зрелые или одинаково подходят для security-sensitive контекста.
- Внешние зависимости могут содержать
unsafeили транзитивно приносить код, который сложнее аудировать. - Некоторые интеграции с платформенными API, драйверами или legacy-библиотеками могут потребовать FFI и
unsafe, что потребует вынесения такого кода в отдельные крейты и усиленного review. - Для команды потребуется закрепить практики Rust code review, threat modeling, fuzzing и dependency governance.
Risks and Mitigations
- Risk: основная проблема Rust в контексте ИБ состоит в том, что гарантии языка действуют только для safe Rust;
unsafe, FFI и внешние зависимости могут обходить часть проверок компилятора и возвращать проект к рискам memory safety.- Mitigation: запретить
unsafeв коде проекта и подтверждать это автоматическими проверками, например#![forbid(unsafe_code)], CI-контролем иcargo geigerили аналогичными инструментами.unsafeво внешних зависимостях допускать только при выполнении требований ИБ к supply chain, а при необходимости низкоуровневых оптимизаций выносить такой код в отдельные крейты с документированными инвариантами, fuzzing, targeted-тестами, security review и явно предоставленными гарантиями безопасности.
- Mitigation: запретить
- Risk: supply chain уязвимости в crate-экосистеме могут попасть в security-sensitive компоненты проекта.
- Mitigation: использовать минимальный набор зависимостей, фиксировать версии через lockfile, применять
cargo auditиcargo deny, проверять лицензии и advisory, ограничивать транзитивные зависимости, формировать SBOM и отдельно ревьюить зависимости, используемые на границе доверенных контуров.
- Mitigation: использовать минимальный набор зависимостей, фиксировать версии через lockfile, применять
- Risk: сложность Rust может привести к ошибочным архитектурным обходам, чрезмерному клонированию данных, блокировкам или неоптимальным realtime-путям.
- Mitigation: закрепить правила проектирования ownership-модели, проводить performance review для критичных путей, использовать benchmarks, tracing, профилирование и load-тесты, а также предпочитать простые и проверяемые структуры данных сложным абстракциям.
- Risk: логические ошибки безопасности возможны даже при отсутствии memory corruption.
- Mitigation: дополнять свойства языка threat modeling, негативными тестами, fuzzing недоверенных входов, проверкой state machine, независимым code review и явной спецификацией security policy.
- Risk: FFI-интеграции с C/C++ библиотеками могут создать неочевидные lifetime, ownership и threading ошибки.
- Mitigation: минимизировать FFI, использовать проверенные библиотеки, выносить FFI-границы в отдельные крейты, документировать владение ресурсами и инварианты безопасности, тестировать границы интеграции с помощью sanitizers и fuzzing, а для критичных зависимостей рассматривать переписывание на safe Rust.