Обучение разработчиков безопасному коду: программа на четыре занятия

Общая программа осведомлённости годится для всех сотрудников, но для разработчиков нужен отдельный разговор — не про фишинг, а про ошибки в собственном коде, которые разработчик вносит сам, не замечая. Общий инструктаж этого не закрывает. Ниже программа на четыре коротких занятия с конкретными примерами, а не абстрактными принципами.
Статья опирается на логику направления «Культура кибербезопасности» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами.
Что должно получиться
| Уровень | Что это значит на практике |
|---|---|
| 2. Гигиенический | Разработчики знают типовые классы ошибок в своём коде и умеют находить их в собственных примерах, а не только слышали термины на одной презентации |
Критерии сформулированы нами по мотивам методики, это ориентир, а не оценка соответствия.
Формат занятий
Часовая лекция про «безопасную разработку в целом» в начале проекта запоминается хуже, чем разбор конкретной ошибки на живом примере. Поэтому формат — четыре занятия по 30–40 минут с интервалом в одну–две недели, каждое про одну группу ошибок с примером кода, который участники разбирают сами (в парах или по одному), а не слушают готовый разбор.
Занятие 1. Внедрение в запросы и команды
Пример для разбора — функция, собирающая SQL-запрос подстановкой строки, и вызов системной команды с параметром от пользователя:
def find_user(conn, name):
return conn.execute("SELECT * FROM users WHERE name = '%s'" % name).fetchall()
def ping(host):
return subprocess.run("ping -c 1 " + host, shell=True)
Задание: подобрать значение параметра, при котором функция сделает не то, что задумано (например, вернёт все записи или допишет к запросу что-то ещё). Разбор: почему параметризованный запрос и вызов без shell=True с явным списком аргументов закрывают проблему, а экранирование кавычек вручную — нет.
Занятие 2. Десериализация и загрузка конфигураций
Пример — загрузка пользовательских данных через pickle и чтение конфигурации через yaml.load без безопасного режима:
def load_session(blob):
return pickle.loads(blob)
def load_config(text):
return yaml.load(text)
Задание: объяснить, почему содержимое, пришедшее не от самого приложения (сессия пользователя, файл конфигурации, загруженный кем-то извне), нельзя десериализовать этими способами. Разбор: чем заменить (JSON вместо pickle для данных извне, yaml.safe_load вместо yaml.load) и почему «мы же доверяем этому источнику» часто оказывается неверным спустя время.
Занятие 3. Криптография и проверка сертификатов
Пример — хэширование пароля слабым алгоритмом и отключённая проверка TLS-сертификата:
def password_hash(p):
return hashlib.md5(p.encode()).hexdigest()
def fetch(requests, url):
return requests.get(url, verify=False)
Задание: найти, где в коде организации встречаются эти две конструкции (поиском по кодовой базе), и обсудить, почему их добавили — обычно «чтобы заработало на тестовом стенде с самоподписанным сертификатом», а потом осталось в продуктиве. Разбор: современные алгоритмы хэширования паролей (не MD5 и не SHA-256 без соли — для паролей нужны специально спроектированные алгоритмы), и как правильно работать с самоподписанными сертификатами на тесте, не отключая проверку совсем.
Занятие 4. Секреты в коде и автоматическая проверка
Пример — токен, зашитый в код как константа. Задание: найти в истории git репозитория компании (если она открыта участникам) случаи, когда токен или пароль случайно попадал в коммит, и обсудить, что происходит после такой публикации (токен считается скомпрометированным, даже если коммит потом удалили — история остаётся). Разбор: куда класть секреты вместо кода, и знакомство с автоматической проверкой, которая теперь ловит часть этих ошибок до код-ревью: bandit в конвейере для Python и аналогичные инструменты для других языков.
Как закрепить, а не оставить разовым мероприятием
- Включите статический анализ (как в занятии 4) в конвейер сборки — тогда разбор ошибки происходит не раз в год на занятии, а в момент, когда разработчик её вносит.
- На код-ревью явно спрашивайте про источники параметров в запросах и командах — простой вопрос «а что если сюда придёт `’; DROP TABLE` » в культуре команды работает лучше любой презентации.
- Через два–три месяца после программы разберите на новом занятии реальную находку из собственного статического анализа или код-ревью (обезличенно) — это держит тему живой, а не разовой.
Показатели, что обучение дало результат
| Показатель | Как посчитать |
|---|---|
| Доля находок статического анализа, закрытых за один спринт | Из трекера задач: находки с меткой безопасности, время от создания до закрытия |
| Число новых находок той же категории спустя квартал после занятия | Сравнение отчётов анализатора за два периода по конкретному коду ошибки (SQL, pickle, hardcoded secret) |
| Участие в занятиях | Доля разработчиков, прошедших все четыре занятия, а не только первое |
Падение числа новых находок одной и той же категории — более честный показатель, чем «отметка о посещении»: обучение, после которого ошибка больше не появляется, сработало независимо от того, помнят ли участники название презентации.
Диагностика
| Симптом | Причина и что делать |
|---|---|
| На занятии тихо, вопросов нет | Формат лекции, а не разбора. Дайте участникам сначала самим найти проблему в примере, затем разбирайте вместе |
| Через полгода те же ошибки в новом коде | Знание не подкреплено автоматической проверкой. Включите статический анализ в конвейер, чтобы ошибка ловилась раньше код-ревью |
| Разработчики считают тему «не их зоной ответственности» | Программа подана как требование ИБ, а не как часть качества кода. Свяжите с код-ревью и обычным процессом разработки, не с отдельным «безопасным» процессом сбоку |
| Примеры воспринимаются как учебные и далёкие от реальности | Используйте обезличенные находки из собственной кодовой базы вместо абстрактных примеров, где это возможно |
Где это в модели зрелости
Материал относится к направлению «Культура кибербезопасности» (материалы направления, карта зрелости). Уровень 2 требует, чтобы обучение было не разовым мероприятием, а воспроизводимой программой с проверкой результата: для разработчиков это означает конкретные примеры из их собственного кода и связь с автоматической проверкой, а не общую презентацию про опасности интернета.
Как проверить
- Программа из четырёх занятий проведена и запланирована на повторение для новых сотрудников.
- Статический анализ, упомянутый на занятии 4, реально включён в конвейер сборки, а не остался темой для обсуждения.
- Число новых находок одной категории снижается от квартала к кварталу после проведения программы.
- Примеры на занятиях основаны на реальном коде организации там, где это возможно, а не только на абстрактных иллюстрациях.
Источники
- Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
- OWASP Top 10: обзор самых частых классов уязвимостей веб-приложений: owasp.org. Международная практика, не российский норматив.


















