---
tags: [конспект, слушателю, БРПО, SQL, SQLite, архитектура]
курс: М БРПО — Специалист по процессам разработки безопасного ПО
занятие: Языки программирования, shift-left и безопасная архитектура реестра компонентов
---

# Конспект занятия

Этот конспект сопровождает две лекции по 90 минут и готовит к трём практическим занятиям по SQL. Сквозной учебный пример дня — **реестр программных компонентов**: небольшая SQLite-база, в которой учитываются название, версия, лицензия, поставщик и критичность компонента.

Реестр из практикума — не полноценная система SCA (анализ состава ПО: какие сторонние компоненты входят в продукт и с какими известными уязвимостями) и не готовый SBOM (машиночитаемый перечень компонентов ПО). Это компактная модель, на которой можно увидеть, как выбор языка, архитектуры, схемы данных и API влияет на безопасность.

**Вопрос дня:**

> Как сделать так, чтобы реестр компонентов не только хранил данные, но и сохранял их целостность, отделял данные от команд и оставлял проверяемые свидетельства безопасной разработки?

## Результаты обучения

К концу дня вы сможете:

- различать уровни абстракции, парадигмы и модели выполнения языков;
- объяснять, почему один язык может относиться сразу к нескольким классам;
- связывать свойства языка и среды выполнения с классами слабостей;
- различать библиотеку, фреймворк и платформу;
- применять shift-left к требованиям, архитектуре, кодированию и тестированию;
- выделять границы доверия и поверхность атаки приложения с базой данных;
- объяснять назначение ограничений схемы SQLite, параметризованных запросов, allowlist, транзакций и соединения только для чтения;
- соотносить результаты практикума с процессами ГОСТ Р 56939-2024 и практиками NIST SSDF v1.1.

## Расписание содержательной части

| Время | Формат | Содержание |
|---|---|---|
| 09:30–11:00 | Лекция 1, 90 минут | Хроника и классификация языков. Влияние выбора языка на безопасность |
| 11:10–12:40 | Лекция 2, 90 минут | Shift-left, компоненты стека и архитектура безопасного реестра |
| 13:30–15:00 | Практика 1, 90 минут | Схема SQLite и ограничения целостности |
| 15:10–16:40 | Практика 2, 90 минут | CWE-89 (SQL-инъекция), параметризация и безопасные динамические запросы |
| 16:50–18:20 | Практика 3, 90 минут | Самостоятельная реализация и регрессионные тесты |

## Лекция 1. Языки программирования: история, классификация и безопасность

## 1. От машинных команд к предметным языкам

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

Выборочные вехи:

1. **Машинный код** задаёт операции в форме, непосредственно исполняемой процессором. Переносимость и контроль ошибок почти полностью лежат на разработчике.
2. **Ассемблер** заменяет числовые коды мнемониками и метками, но остаётся тесно связан с архитектурой процессора.
3. **Высокоуровневые языки** позволяют описывать алгоритмы независимо от конкретных регистров и адресов. В эту линию входят ранние языки общего назначения, а позднее C, Pascal и другие семейства.
4. **C** формировался в Bell Labs вместе с развитием UNIX как язык системного программирования. Он сочетает высокоуровневые конструкции с прямым доступом к памяти и системным ресурсам.
5. **C++** развивал идеи «C with Classes» и добавлял средства абстракции, не отказываясь от системного уровня и совместимости с большой частью модели C.
6. **Python** создавался как язык с акцентом на читаемость и быструю разработку; работа над первой реализацией началась в конце 1980-х годов.
7. **Предметно-ориентированные языки**, включая SQL, позволяют описывать задачу в терминах конкретной области. В SQL разработчик формулирует требуемый результат над данными, а способ выполнения выбирает СУБД.

Это не линейная замена «старого плохого» на «новое хорошее». Ассемблер, C, C++, Python и SQL решают задачи разного уровня и часто сосуществуют в одном продукте.

## 2. Четыре независимые оси классификации

Ошибочно пытаться отнести каждый язык к одной ячейке. Полезнее рассматривать несколько независимых осей.

### 2.1. Уровень абстракции

- **Низкоуровневые средства** позволяют напрямую управлять регистрами, адресами, представлением данных и инструкциями процессора.
- **Высокоуровневые средства** скрывают часть деталей оборудования за типами, объектами, коллекциями, исключениями и библиотечными API.

Граница условна. C высокоуровневее ассемблера, но предоставляет значительно больше прямого контроля памяти, чем Python.

### 2.2. Парадигма

- **Императивная:** программа задаёт последовательность изменений состояния — «как выполнить».
- **Декларативная:** программа описывает желаемое условие или результат — «что получить».
- **Объектно-ориентированная:** данные и поведение группируются вокруг объектов, типов и отношений между ними.
- **Функциональная:** вычисления выражаются через функции и композицию, по возможности с ограничением изменяемого состояния.

Парадигмы не взаимоисключающие. Python и C++ поддерживают несколько стилей. Объектно-ориентированная программа обычно содержит императивный код. SQL декларативен, но его использование в приложении окружено императивной логикой.

### 2.3. Модель выполнения

- трансляция в машинный код заранее;
- выполнение интерпретатором;
- выполнение байт-кода виртуальной машиной;
- JIT-компиляция во время работы;
- сочетание нескольких подходов.

Фраза «язык компилируемый» или «язык интерпретируемый» часто описывает популярную реализацию, а не неизменное свойство самого языка.

### 2.4. Область применения

- язык общего назначения;
- системный язык;
- язык сценариев и автоматизации;
- язык запросов;
- предметно-ориентированный язык, или DSL.

**SQL — декларативный DSL для работы с данными.** Он не заменяет Python или C++, а образует отдельный слой системы.

## 3. Как язык влияет на безопасность

Язык и среда выполнения меняют:

- какие ошибочные состояния можно выразить;
- какие проверки выполняются автоматически;
- где находится граница между безопасным и небезопасным API;
- какие средства анализа доступны;
- какова доля нативного и стороннего кода;
- насколько предсказуемы сборка и развёртывание.

### 3.1. Безопасность памяти

В C и C++ разработчик часто управляет временем жизни объектов, указателями и границами буферов. Ошибки этого слоя связаны с семействами слабостей работы с памятью, включая [CWE-119](https://cwe.mitre.org/data/definitions/119.html) (CWE — каталог типовых слабостей программного обеспечения, который ведёт MITRE; номер обозначает конкретную слабость).

В языках с автоматическим управлением памятью и обязательными проверками границ многие такие ошибки нельзя получить обычной операцией над коллекцией. Но это не означает абсолютной безопасности:

- интерпретатор и расширения могут быть написаны на C или C++;
- уязвимость может находиться в сторонней библиотеке;
- остаются логические ошибки, инъекции, нарушения авторизации и небезопасная конфигурация;
- чрезмерное потребление памяти и процессорного времени остаётся возможным.

Выбор языка сокращает одни классы рисков, но не отменяет моделирование угроз и проверку архитектуры. Рекомендации по переходу к memory-safe подходам рассматриваются в материалах [CISA](https://www.cisa.gov/resources-tools/resources/case-memory-safe-roadmaps).

### 3.2. Валидация и состояние

[CWE-20](https://cwe.mitre.org/data/definitions/20.html) относится к ненадлежащей проверке входных данных. Проблема не решается автоматически статической или динамической типизацией:

- тип `str` не доказывает, что строка является допустимым SPDX-идентификатором (SPDX — стандарт описания состава ПО; здесь используется его словарь идентификаторов лицензий);
- тип `int` не доказывает, что значение находится в разрешённом диапазоне;
- объектная модель не доказывает уникальность записи в базе;
- проверка только в пользовательском интерфейсе обходится другим клиентом.

Нужны одновременно правила предметной области, проверка в коде и ограничения в хранилище.

### 3.3. Инъекции

SQL-инъекция возникает не потому, что SQL «небезопасен», а потому, что приложение смешивает **команду** и **данные** в одной строке.

Упрощённый небезопасный шаблон:

```python
sql = "SELECT ... WHERE name = '" + external_value + "'"
```

Значение, пришедшее извне, становится частью грамматики SQL. Это соответствует [CWE-89](https://cwe.mitre.org/data/definitions/89.html).

Принцип безопасного интерфейса:

```python
sql = "SELECT ... WHERE name = ?"
parameters = (external_value,)
```

Текст команды и значения передаются драйверу отдельно. Документация Python прямо рекомендует placeholders вместо строкового форматирования при передаче значений в SQL.

> Параметризация предназначена для **значений**, но не для имён таблиц, столбцов и направлений сортировки. Динамические идентификаторы выбирают из заранее заданного allowlist.

## 4. Сравнение языков без ложного рейтинга

| Критерий | C/C++ | Python | SQL |
|---|---|---|---|
| Основная роль в учебном примере | возможная реализация системного продукта | логика приложения и безопасный API | схема и операции над данными |
| Управление памятью | высокий контроль и высокая ответственность разработчика | преимущественно автоматическое | управляется СУБД |
| Типичные риски | ошибки памяти, неопределённое поведение, небезопасные API | инъекции, логика, зависимости, конфигурация | избыточные права, небезопасная динамика запросов, ошибки схемы |
| Сильная сторона анализа | компиляторы, санитайзеры, SAST (статический анализ кода без запуска), строгие профили | тесты, типизация, линтеры, SAST | ограничения схемы, анализ запросов, журналирование |
| Что не решает язык | архитектурные ошибки, права, цепочку поставок | те же классы плюс риски нативных расширений | доверие к вызывающему приложению |

Цель выбора языка — не найти «самый безопасный язык», а согласовать:

1. модель угроз;
2. требования к производительности и платформе;
3. допустимые классы дефектов;
4. доступные средства верификации;
5. компетенции команды;
6. жизненный цикл зависимостей;
7. требования к сопровождению и поставке.

## 5. Контрольные вопросы к лекции 1

Запишите ответы до перерыва:

1. Почему «высокоуровневый» и «объектно-ориентированный» — не противоположные категории?
2. Какие классы слабостей уменьшает автоматическое управление памятью, а какие оставляет?
3. Почему SQL является языком программирования, хотя в нём обычно не описывают пошаговый алгоритм?
4. Что в вашей предметной области важнее при выборе языка: безопасность памяти, проверяемость, экосистема или ограничения платформы?
5. На какой границе в приложении Python + SQLite возникает риск CWE-89?

## Лекция 2. Shift-left, компоненты стека и безопасная архитектура

## 6. Shift-left как изменение точки принятия решения

Shift-left означает, что требования и проверки безопасности выполняются как можно раньше и повторяются на протяжении жизненного цикла. NIST SSDF v1.1 отмечает, что раннее рассмотрение безопасности обычно требует меньше усилий и затрат, чем исправление тех же проблем позднее.

Применительно к реестру компонентов:

| Поздняя реакция | Shift-left |
|---|---|
| после инцидента запретить опасный запрос | заранее определить правило «значения только через параметры» |
| исправлять дубликаты в готовой базе | задать `UNIQUE` в схеме |
| искать потерянную запись аудита | проектировать изменение и аудит как одну транзакцию |
| вручную проверять каждую сортировку | разрешить только фиксированный набор столбцов |
| надеяться, что читатель не запишет данные | открыть отдельное соединение в режиме `mode=ro` |

Shift-left — это не только ранний запуск сканера. Он начинается с архитектурного решения, которое уменьшает число небезопасных вариантов реализации.

## 7. Библиотека, фреймворк и платформа

### Библиотека

Библиотека предоставляет функции или классы, которые вызывает ваш код. В практикуме модуль стандартной библиотеки Python `sqlite3` предоставляет соединение, курсор, параметризацию и управление транзакциями.

### Фреймворк

Фреймворк задаёт каркас приложения и вызывает пользовательский код в предусмотренных точках. Это инверсия управления: жизненным циклом значительной части приложения управляет не ваш модуль.

### Платформа или движок

Платформа определяет среду выполнения и доступные сервисы. В учебном примере участвуют:

- интерпретатор CPython;
- библиотечный интерфейс `sqlite3`;
- движок SQLite;
- файловая система, где хранится база.

Границы важнее названий. Уязвимость или небезопасная конфигурация любого слоя может повлиять на продукт.

## 8. Сторонние компоненты как часть архитектуры

Компонент становится частью поверхности атаки продукта, даже если команда не написала его исходный код. Для каждого компонента нужны как минимум:

- однозначное имя и версия;
- источник или поставщик;
- лицензионная информация;
- контекст использования;
- ответственное лицо или роль;
- сведения, необходимые для оценки риска и обновления.

NIST SSDF v1.1, практика **PW.4.1**, рассматривает приобретение и сопровождение достаточно защищённых компонентов, включая библиотеки, модули, middleware и фреймворки. Реестр помогает выполнить часть этой работы, но сам по себе не проверяет происхождение, уязвимости, лицензионную совместимость и целостность поставки.

## 9. Архитектура учебного реестра

Поток данных:

```text
внешнее значение
      ↓
проверка формата и бизнес-правил
      ↓
API операций реестра
      ↓
параметризованный SQL / allowlist идентификаторов
      ↓
ограничения и транзакции SQLite
      ↓
файл базы данных
```

Защитные слои не дублируют друг друга:

- **валидация приложения** выдаёт понятную ошибку до обращения к БД;
- **параметризация** разделяет SQL-код и значения;
- **allowlist** ограничивает динамические идентификаторы;
- **ограничения схемы** защищают целостность независимо от вызывающего кода;
- **транзакция** не допускает частичного результата;
- **режим только для чтения** уменьшает полномочия;
- **тесты** подтверждают ожидаемое поведение и предотвращают регрессии.

## 10. Мини-модель угроз

### Активы

- перечень компонентов и их версий;
- сведения о лицензиях и поставщиках;
- оценка критичности;
- журнал значимых изменений;
- доступность и целостность файла базы.

### Точки входа

- поля добавления компонента;
- строка поиска;
- параметр сортировки;
- новая лицензия;
- идентификатор изменяемой записи;
- путь к файлу базы.

### Основные сценарии

| Сценарий | Возможное последствие | Архитектурный ответ |
|---|---|---|
| значение изменяет смысл SQL | чтение или изменение неразрешённых данных | параметры запроса |
| имя столбца формируется из ввода | внедрение в `ORDER BY` | allowlist и отображение «вход → константа» |
| `%` и `_` неожиданно работают как маски | избыточная выборка | явное экранирование метасимволов `LIKE` |
| недопустимая критичность попадает в БД | нарушение качества и аналитики | проверка приложения и `CHECK` |
| обновление выполнено, аудит не записан | потеря трассируемости | единая транзакция |
| читатель получает возможность записи | несанкционированное изменение | соединение только для чтения |
| удаление компонента оставляет «висячие» события | нарушение ссылочной целостности | внешний ключ и ограничение удаления |

Это учебная модель. В промышленной системе дополнительно рассматривают аутентификацию, авторизацию, резервное копирование, журнал доступа, защиту файла БД, конкурентные изменения, криптографическую целостность и доверие к поставщикам.

## 11. Схема как исполняемое требование

В `schema.sql` используются:

- `NOT NULL` — обязательность;
- `CHECK` — допустимый диапазон или множество значений;
- `UNIQUE` — защита от определённого класса дубликатов;
- `FOREIGN KEY` — связь события аудита с компонентом;
- `ON DELETE RESTRICT` — запрет удаления, нарушающего связь;
- `STRICT` — более строгая проверка типов таблицей SQLite.

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

В учебном коде `PRAGMA foreign_keys = ON` выполняется для каждого соединения, которое должно обеспечивать внешние ключи. Настройка одного соединения не заменяет настройку остальных.

## 12. Параметры, идентификаторы и шаблоны

### Значения

Значения передаются через placeholders:

```python
connection.execute(
    "SELECT id, name FROM example WHERE name = ?",
    (external_value,),
)
```

Кортеж `(external_value,)` содержит данные. Драйвер не подставляет их простой склейкой строк.

Запятая в `(external_value,)` обязательна: запись `(external_value)` без запятой — это не кортеж, а просто значение в скобках. Драйвер получит строку вместо кортежа, воспримет каждый её символ как отдельный параметр и завершится ошибкой `sqlite3.ProgrammingError` о неверном числе параметров.

### Идентификаторы

Имя столбца нельзя передать через `?`. Если пользователь выбирает сортировку, приложение сопоставляет его выбор с одной из заранее заданных SQL-констант:

```text
пользовательское значение → проверка по allowlist → фиксированный идентификатор
```

Прямое включение непроверенного `sort_by` в SQL недопустимо.

### `LIKE`

В шаблоне `LIKE` символы `%` и `_` имеют специальное значение. Если бизнес-требование — искать их как обычные символы, параметризации недостаточно: значение дополнительно преобразуется по правилам выбранного `ESCAPE`.

Наглядный пример «до и после». Пользователь ищет строку `100%`. Без экранирования `%` означает «любая последовательность символов», поэтому поиск найдёт и `1000`, и `100 штук` — заведомо лишние записи. После экранирования фрагмент превращается в `100!%`, а запрос выполняется с указанием `ESCAPE '!'`: теперь `%` ищется как обычный символ. Сам служебный символ `!` в данных удваивается первым (`!` → `!!`), иначе он исказит уже вставленные замены `!%` и `!_`.

Параметризация защищает границу «код — данные», а экранирование `LIKE` обеспечивает требуемую семантику поиска. Это разные задачи.

Отдельная особенность SQLite: оператор `LIKE` нечувствителен к регистру только для символов ASCII, то есть латиницы. Для кириллицы сравнение по умолчанию регистрозависимо: шаблон `'компонент%'` не найдёт строку `Компонент`. Учебные данные практикума состоят из латинских имён, поэтому на занятии `LIKE` ведёт себя регистронезависимо.

## 13. Транзакция как граница целостности

Операция «изменить лицензию» состоит минимум из двух записей:

1. обновить компонент;
2. добавить событие аудита.

Без общей транзакции возможен частичный результат. Безопасное требование формулируется так:

> либо изменение и событие аудита фиксируются вместе, либо не фиксируется ничего.

Контекстный менеджер соединения Python может зафиксировать успешную транзакцию и откатить её при исключении. Но разработчик всё равно обязан правильно определить начало и конец бизнес-операции.

Поясним механику. Контекстный менеджер — это объект, который используется в конструкции `with` и автоматически выполняет завершающие действия при выходе из блока, даже если внутри произошло исключение. Для соединения `sqlite3` завершающее действие — это `COMMIT` при нормальном выходе и `ROLLBACK` при исключении. Сам оператор `with` транзакцию не начинает: при стандартных настройках её неявно открывает первая изменяющая команда (`UPDATE`, `INSERT`) внутри блока, а `with` отвечает только за корректное завершение:

```python
with connection:  # COMMIT или ROLLBACK на выходе
    connection.execute("UPDATE components SET license_spdx = ? WHERE id = ?", (new_license, component_id))
    connection.execute("INSERT INTO audit_events (event_type, component_id) VALUES (?, ?)", ("license_changed", component_id))
# выход без исключения -> COMMIT: обе записи видны всем
# исключение внутри блока -> ROLLBACK: не видна ни одна
```

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

## 14. Минимальные полномочия

Если функции нужен только отчёт, ей не требуется право записи. SQLite поддерживает URI-подключение в режиме только для чтения:

```python
sqlite3.connect("file:path/to/database?mode=ro", uri=True)
```

Точный URI должен формироваться корректно для выбранного пути. Режим `mode=ro` — дополнительный слой, а не замена прав доступа файловой системы и организационного разграничения ролей.

## 15. Что является свидетельством процесса

Учебный комплект создаёт несколько видов артефактов:

| Артефакт | Что он подтверждает | Чего он не подтверждает |
|---|---|---|
| `schema.sql` | формализованные ограничения данных | корректность всех операций приложения |
| модель угроз слушателя | рассмотренные активы, входы и сценарии | полноту промышленной модели угроз |
| `step3_student.py` | реализацию заданного API | отсутствие всех возможных уязвимостей |
| результат `test_student.py` | прохождение конкретных регрессионных проверок | полный статический или динамический анализ |
| краткое обоснование решений | осознанный выбор мер | соответствие всей организации стандарту |

Зелёный тест — свидетельство по одному требованию, а не сертификат безопасности продукта.

## 16. Нормативная и методическая привязка

### ГОСТ Р 56939-2024

| Процесс | Связь с занятием | Проверяемый учебный артефакт |
|---|---|---|
| **5.6 — разработка архитектуры** | границы доверия, слои защиты, потоки записи и чтения | схема архитектуры и обоснование решений |
| **5.7 — моделирование угроз** | активы, точки входа, CWE-89, нарушение целостности и избыточные полномочия | заполненная мини-модель угроз |
| **5.8 — правила кодирования** | параметры для значений, allowlist для идентификаторов, обработка ошибок | самостоятельная реализация |
| **5.10 — статический анализ** | правило поиска небезопасной сборки SQL и контроль конфигурации анализатора | сформулированное правило проверки; запуск тестов не заменяет SAST |
| **5.18 — функциональное тестирование** | позитивные и негативные сценарии операций реестра | результат `test_student.py` |

Официальная карточка стандарта: [ГОСТ Р 56939-2024 в Федеральном информационном фонде стандартов](https://protect.gost.ru/gost/details/f3818925-a96f-4f55-96e9-46b44720ee64). Стандарт действует с 20 декабря 2024 года и заменяет редакцию 2016 года.

### NIST SSDF v1.1

| Практика | Применение в учебном дне |
|---|---|
| **PW.1.1** | моделирование угроз, рисков и поверхности атаки |
| **PW.1.2** | фиксация требований безопасности, рисков и архитектурных решений |
| **PW.2.1** | проверка архитектуры относительно требований и рисков |
| **PW.4.1** | учёт и сопровождение используемых программных компонентов |
| **PW.5.1** | безопасные практики кодирования, применимые к Python и SQL |
| **PW.6.1** | применение актуального интерпретатора и инструментов, поддерживающих защитные возможности |

NIST SSDF — риск-ориентированная рамка результатов, а не инструкция по одному инструменту. Основной источник: [NIST SP 800-218, SSDF Version 1.1](https://csrc.nist.gov/pubs/sp/800/218/final).

## 17. Термины дня

| Термин | Рабочее определение |
|---|---|
| Парадигма | общий способ выражения вычислений и организации программы |
| DSL | язык, ориентированный на конкретную предметную область |
| Shift-left | раннее и повторяемое выполнение работ по безопасности в жизненном цикле |
| Граница доверия | место, где меняется уровень доверия к данным или исполнителю |
| Поверхность атаки | доступные точки взаимодействия, через которые можно воздействовать на систему |
| Parameterized query | SQL-команда с отдельно переданными значениями |
| Allowlist | заранее заданное множество разрешённых вариантов |
| Транзакция | атомарная единица изменений: полностью фиксируется или полностью откатывается |
| Least privilege | предоставление только тех полномочий, которые необходимы для задачи |
| Регрессионный тест | проверка, не позволяющая ранее исправленному дефекту вернуться |
| CWE | каталог типовых слабостей программного обеспечения, который ведёт MITRE; SQL-инъекции соответствует CWE-89 |
| SAST | статический анализ кода: поиск дефектов без запуска программы |
| SCA | анализ состава ПО: инвентаризация компонентов и их версий, включая транзитивные зависимости, с проверкой известных уязвимостей и лицензий |
| SBOM | машиночитаемый перечень компонентов программного обеспечения |
| SPDX | открытый стандарт описания состава и цепочки поставки ПО (формат SBOM); на занятии используется его перечень идентификаторов лицензий — отсюда имя колонки `license_spdx` |
| CI | автоматический запуск проверок при каждом изменении кода |
| Quality gate | набор проверок, без прохождения которых результат не считается готовым |
| RED/GREEN | состояния прогона тестов: сначала красный — задание не выполнено, цель — зелёный |

## 18. Авторитетные источники

### Безопасная разработка и архитектура

- [ГОСТ Р 56939-2024 — официальная карточка Росстандарта](https://protect.gost.ru/gost/details/f3818925-a96f-4f55-96e9-46b44720ee64)
- [NIST SP 800-218 — Secure Software Development Framework Version 1.1](https://csrc.nist.gov/pubs/sp/800/218/final)
- [ISO/IEC 27034-1 — Application security](https://www.iso.org/standard/44378.html)
- [ISO/IEC 24772-1:2024 — Guidance to avoiding vulnerabilities in programming languages](https://www.iso.org/standard/83629.html)
- [CISA — The Case for Memory Safe Roadmaps](https://www.cisa.gov/resources-tools/resources/case-memory-safe-roadmaps)

### История языков

- [Dennis M. Ritchie — The Development of the C Language](https://www.bell-labs.com/usr/dmr/www/chist.pdf)
- [Standard C++ Foundation — C++ FAQ: Big Picture](https://isocpp.org/wiki/faq/big-picture)
- [Python — Foreword for “Programming Python”](https://www.python.org/doc/essays/foreword/)
- [Python documentation — General Python FAQ](https://docs.python.org/3/faq/general.html)

### SQL и SQLite

- [MITRE CWE-89 — SQL Injection](https://cwe.mitre.org/data/definitions/89.html)
- [OWASP SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)
- [Python documentation — `sqlite3`](https://docs.python.org/3/library/sqlite3.html)
- [SQLite — Foreign Key Support](https://www.sqlite.org/foreignkeys.html)
- [SQLite — Security](https://www.sqlite.org/security.html)
- [SQLite — URI Filenames and `mode=ro`](https://www.sqlite.org/uri.html)

## 19. Перед практикумом

Не переходя к коду, сформулируйте:

1. три требования безопасности к реестру;
2. две границы доверия;
3. один сценарий CWE-89;
4. одно решение, которое должно находиться в архитектуре, а не только в инструкции разработчику;
5. один проверяемый артефакт для каждого из процессов 5.6, 5.7, 5.8, 5.10 и 5.18.

Ответы сохраните в своих заметках. Практикум не содержит готовой реализации самостоятельного задания.
