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

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

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

Статья опирается на логику направления «Культура кибербезопасности» из методики зрелости Группы Сбер (источник); это методика для крупных компаний, мы используем её как ориентир и пересказываем своими словами.

Что должно получиться

Уровень Что это значит на практике
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 требует, чтобы обучение было не разовым мероприятием, а воспроизводимой программой с проверкой результата: для разработчиков это означает конкретные примеры из их собственного кода и связь с автоматической проверкой, а не общую презентацию про опасности интернета.

Как проверить

  1. Программа из четырёх занятий проведена и запланирована на повторение для новых сотрудников.
  2. Статический анализ, упомянутый на занятии 4, реально включён в конвейер сборки, а не остался темой для обсуждения.
  3. Число новых находок одной категории снижается от квартала к кварталу после проведения программы.
  4. Примеры на занятиях основаны на реальном коде организации там, где это возможно, а не только на абстрактных иллюстрациях.

Источники

  • Методика оценки уровня зрелости кибербезопасности компании, Группа Сбер: sberbank.ru.
  • OWASP Top 10: обзор самых частых классов уязвимостей веб-приложений: owasp.org. Международная практика, не российский норматив.

Комментарии закрыты.