TGViewer
Искусство. Код... ИИ? Искусство. Код... ИИ? @art_code_ai · 707 subscribers
Post #126 1.43K
🧩 Принципы и паттерны безопасной разработки: DIP

Часть 4.

Принцип инверсии зависимостей (Dependency Inversion Principle, DIP) утверждает: модули верхнего уровня не должны зависеть от модулей нижнего уровня, оба должны зависеть от абстракций. При этом не абстракции должны зависеть от деталей, а детали — от абстракций.

С точки зрения безопасности, нарушение DIP означает, что высокоуровневая логика (принятие решений, обработка входных данных) жёстко привязана к конкретной низкоуровневой реализации. Когда эта реализация меняется или расширяет поверхность атаки — высокоуровневый модуль наследует проблему автоматически, без какого-либо контроля на своей стороне.

💡 Пример

// С нарушением DIP
class DataBinder {
void bind(Object target, Map<String,String> params) {
for (PropertyDescriptor pd :
Introspector.getBeanInfo(target.getClass())
.getPropertyDescriptors()) {
if (params.containsKey(pd.getName()))
pd.getWriteMethod().invoke(target, params.get(pd.getName()));
}
}
}

// С соблюдением DIP
interface BindablePropertyResolver {
List<BindableProperty> resolve(Class<?> type);
}

class DataBinder {
private final BindablePropertyResolver resolver;

void bind(Object target, Map<String,String> params) {
for (BindableProperty bp : resolver.resolve(target.getClass())) {
if (params.containsKey(bp.name()) && bp.isSafe())
bp.set(target, params.get(bp.name()));
}
}
}


Абстракция BindablePropertyResolver контролируется высокоуровневым модулем и определяет контракт: что можно связывать, а что — нет. Даже если интроспекция обнаружит новые свойства, они не станут доступны без явного разрешения.

Помимо архитектурного разделения, главным правилом остается биндинг входных данных строго к выделенным DTO (Data Transfer Objects), а не к доменным сущностям или объектам фреймворка. DTO содержит только явно разрешенные поля, что исключает динамический биндинг опасных свойств.

Нарушения DIP провоцируют:

• CWE-913: Improper Control of Dynamically-Managed Code Resources
• CWE-470: Use of Externally-Controlled Input to Select Classes or Code
• CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes

🐛 Жизненное

CVE-2022-22965 — Spring Framework RCE, она же Spring4Shell (CVSS 9.8).

Механизм привязки параметров (data binding) в Spring MVC — высокоуровневый модуль, отвечающий за маппинг HTTP-параметров в свойства Java-объектов. Внутри он напрямую зависит от низкоуровневого Java Beans Introspection API (CachedIntrospectionResults → java.beans.Introspector), рекурсивно обходящего цепочки геттеров/сеттеров.

На JDK 8 существовал чёрный список: Spring блокировал доступ к class.classLoader. Но в JDK 9 у Class появился новый геттер — getModule(). Через него открылся обходной путь class.module.classLoader, не попавший в чёрный список. Цепочка:

class.module.classLoader.resources.context.parent.pipeline.first.*

позволяла модифицировать конфигурацию Tomcat AccessLogValve — атакующий менял путь, паттерн и суффикс лога, записывая на диск JSP-файл (web shell).

Нарушение DIP здесь в том, что data binding напрямую зависел от конкретного механизма интроспекции (низкоуровневая деталь), без абстракции, определяющей контракт: какие свойства разрешено связывать. Когда деталь (набор доступных PropertyDescriptor-ов) изменилась из-за развития JDK — поверхность атаки расширилась без единого изменения в коде самого Spring.

🔧 Как пофиксили

Spring не стал внедрять глобальный белый список (чтобы не сломать обратную совместимость), и добавил чёрный, на уровне интроспекции. Доступ к свойствам Class, classLoader и protectionDomain был полностью заблокирован, что разорвало опасную цепочку... до следующего витка развития JDK, видимо 😬

💻 Как насчет композиционных языков?

Оставим это на правах домашнего задания: подумать, как Rust поощряет DIP через трейты, а Go — делая упор на простоту, снижение шаблонного кода и неявные интерфейсы.

⚠ TL;DR: Если модуль верхнего уровня напрямую зависит от деталей реализации нижнего — любое изменение внизу может молча расширить поверхность атаки наверху. Инвертируйте зависимость: пусть высокоуровневый модуль определяет контракт допустимых данных, а низкоуровневый — реализует его. А на входе всегда используйте DTO.

#безопасность_кода #гайд
  • ❤ 2
  • 👍 1
  • 💯 1
More from @art_code_ai
  1. Sep 29, 2026Объяснили с Раддой Юрьевой на Хабре, почему смешивать формальные и ИИшные подходы в задача…
  2. Sep 27, 2026🔗 Старый добрый аппсек, часть 2 Продолжаем вспоминать ключевые вехи аппсека и смежных обл…
  3. Sep 26, 2026Post #155
  4. Sep 24, 2026🔗 Старый добрый аппсек, часть 1 ...совершенно незаслуженно задвинутый на второй план ИИ-х…
  5. Sep 23, 2026Post #153
  6. Sep 21, 2026👨‍💻 Продуктивные выходные Как-то незаметно (и неожиданно) для себя с удовольствием провё…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →