Расследуйте и предотвратите регрессию безопасности

КибербезопасностьBeginner
Практиковаться сейчас

Введение

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

Вы проследите реальные свидетельства запросов, остановите новые утечки, замените раскрытые учётные данные и добавите утверждение, блокирующее действительно допускающий утечку кандидат. Исторические журналы остаются свидетельствами; документ исследования не требуется. Локальная система выдачи, клиент, сервис, контрольные варианты сравнения и средства работы с артефактом подготовлены.

Найдите реальное событие инцидента

На этом шаге вы сопоставите запрос с текущей версией журналирования и конфигурацией.

cd /srv/ticket-regression

tail -n 5 читает последние пять строк, сохраняя небольшой объём просмотра. Используйте разрешённое чтение администратором для подготовленного журнала сервиса:

sudo tail -n 5 /opt/labex-ticket-regression/requests.log

Найдите request_id=initial-001, version=logging-v2, path=/tickets и status=200. Этот исторический запрос завершился успешно, но та же строка включает Authorization и старый вымышленный токен. Все значения относятся только к этой изолированной лабораторной работе.

grep выводит строки, содержащие переданный текстовый шаблон. Одинарные кавычки удерживают этот буквальный шаблон вместе:

sudo grep 'request_id=initial-001' /opt/labex-ticket-regression/requests.log
cat logging.conf

include_authorization = true объясняет чувствительное поле. Время события, идентификатор запроса, версия и статус связывают наблюдаемое поведение с активной конфигурацией. Сохраните исходный журнал; его стирание удалило бы свидетельства, а не предотвратило будущую утечку.

Остановите запись чувствительных полей в новых событиях

На этом шаге вы измените политику журналирования, сохранив полезные поля аудита.

nano logging.conf

Используйте:

[logging]
include_authorization = false

Сохраните с помощью Ctrl+O, Enter и Ctrl+X. Примените сохранённую конфигурацию через подготовленную точку входа перезапуска:

bash restart.sh

Дайте новому запросу проверки работоспособности известный идентификатор. X-Request-ID — заголовок запроса, используемый для сопоставления его нового события:

curl -H 'X-Request-ID: after-policy-fix' http://127.0.0.1:8080/health
sudo grep 'request_id=after-policy-fix' /opt/labex-ticket-regression/requests.log

Ожидаются время, версия, идентификатор, путь и status=200, без поля Authorization. Старое событие initial-001 остаётся. Оценивайте новые события по их собственным идентификаторам, не требуя отсутствия секретов в каждой исторической строке.

Отзовите и замените раскрытые учётные данные

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

Изменение политики журналов не делает раскрытое значение недействительным. Отзовите его идентификатор управления:

course-token revoke legacy
curl -i -H 'Authorization: Bearer labex_012345abcdefghijklmnopqrstuvwxyz' http://127.0.0.1:8080/tickets

Ожидается 401. Теперь выпустите замену, не выводя её:

course-token issue /srv/ticket-regression/api.token

Защитите её по схеме администратор/группа клиента из лабораторных работ по правам и токенам:

sudo chown root:deskclient api.token
sudo chmod 640 api.token

Значение создала система выдачи; вы лишь задали доступ. Не копируйте его в исходный код теста, клиентский скрипт или письменный отчёт.

Восстановите клиент, читающий файл

На этом шаге вы заставите существующий клиент использовать защищённую замену.

nano sender.sh

Сохраните ту же форму чтения файла, которая изучалась ранее:

#!/bin/bash
exec sudo -u deskclient /usr/bin/python3 /opt/labex-ticket-regression/send.py --token-file /srv/ticket-regression/api.token

Используйте Ctrl+O, Enter, Ctrl+X.

bash sender.sh

Ожидаются HTTP 200 и исходная заявка Printer offline. Прочитайте недавние рабочие события:

sudo tail -n 5 /opt/labex-ticket-regression/requests.log

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

Разберите, почему существующий тест пропустил утечку

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

cat test_security.py

Позитивный тест использует шаблон запроса из лабораторной работы по написанию тестов. Подготовленное средство api предоставляет token из источника учётных данных целевого сервиса и возвращает реальный статус HTTP, тело и фактическое событие журнала этого запроса. "Bearer " + token соединяет две строки в значение заголовка; само значение не копируется в исходный код.

Два отдельных контрольных варианта используют публичный вымышленный тестовый токен: good не включает чувствительные поля журналов, а logging-regression намеренно записывает тестовый токен. Они не используют и не раскрывают вашу новую рабочую замену.

course-regression-tests good
course-regression-tests logging-regression

Сейчас оба проходят test_valid_token: статус и бизнес-данные остаются корректными в любой реализации. Недостающее требование касается реального события в response["log"]. Каждый запрос вспомогательного средства использует уникальный идентификатор, поэтому возвращённый журнал относится к этому новому запросу, а не к постороннему историческому событию.

Добавьте реальное утверждение о скрытии чувствительных данных в журнале

На этом шаге вы расширите тест требованиями как отсутствия, так и наличия содержимого в новом событии.

Python in проверяет, встречается ли одна строка внутри другой. not in требует её отсутствия. Это утверждения о фактическом возвращённом тексте журнала, а не о вручную предоставленном файле свидетельств.

nano test_security.py

Сохраните позитивный тест и используйте этот полный файл:

from api import request, token

def test_valid_token():
    response = request("/tickets", {"Authorization": "Bearer " + token})
    assert response["status"] == 200
    assert response["body"] == {"tickets": [{"id": 1, "title": "Printer offline"}]}

def test_log_is_redacted():
    response = request("/tickets", {"Authorization": "Bearer " + token})
    assert response["status"] == 200
    assert "Authorization" not in response["log"]
    assert token not in response["log"]
    assert "request_id=" in response["log"]
    assert "path=/tickets" in response["log"]
    assert "status=200" in response["log"]

Сохраните с помощью Ctrl+O, Enter, Ctrl+X. Новый тест запрещает чувствительное поле и значение учётных данных, требуя при этом идентификатор запроса, бизнес-путь и успешный статус. Очистка журнала нарушила бы эти позитивные требования.

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

Докажите, что тест обнаруживает известную регрессию

На этом шаге вы проверите новое утверждение на безопасном поведении и поведении с намеренной утечкой.

course-regression-tests good

Ожидается прохождение обоих тестов.

course-regression-tests logging-regression

Ожидается провал только test_log_is_redacted с AssertionError и кодом завершения 1. Это намеренное обнаружение, а не предложение ослабить утверждение. Позитивный бизнес-тест должен продолжать проходить.

course-regression-tests live

Оба должны пройти на вашем реальном исправленном сервисе. Эти тесты проверяют только события своих новых запросов; исходное историческое событие утечки намеренно сохранено. Синтаксическая ошибка, ошибка соединения или безусловный провал не показали бы эффективное покрытие скрытия чувствительных данных.

Подключите новый тест к доставке кандидата

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

Подготовленный контрольный барьер использует ту же структуру проверка/сборка/тест/развёртывание, что и предыдущая лабораторная работа о барьере. build.sh упаковывает исходный сервер и текущую политику журналирования, затем запускает этого реального кандидата на отдельном локальном порту. Существующий test.sh проверяет его поведение с действующим/отсутствующим/неверным токеном; журналы он не проверяет.

nano gate.sh

Добавьте вызов регрессионной проверки после сборки и перед существующими функциональными тестами. Используйте:

#!/bin/bash
bash checks.sh
status=$?
if [ "$status" -eq 1 ]; then
    exit 1
fi
if [ "$status" -ne 0 ]; then
    exit 2
fi
bash build.sh || exit 2
bash regression.sh candidate || exit 2
bash test.sh || exit 2
bash deploy.sh

Сохраните с помощью Ctrl+O, Enter, Ctrl+X. candidate выбирает реальное только что собранное приложение, поэтому добавленное утверждение защищает артефакт, который собираются развернуть. || exit 2 останавливает доставку, если его тесты не проходят.

bash gate.sh

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

Подтвердите новые события и сохранённую историю

На этом шаге вы проверите развёрнутое поведение и осмыслите свидетельства без написания файла отчёта.

bash sender.sh
sudo tail -n 5 /opt/labex-ticket-regression/requests.log

Новые рабочие события должны сохранять время, реальную развёрнутую версию, идентификаторы запросов, пути и статусы без учётных данных. Теперь развёрнутая версия — хеш артефакта вместо исходной метки logging-v2.

sudo grep 'request_id=initial-001' /opt/labex-ticket-regression/requests.log

Исходное событие инцидента всё ещё существует. Его старый токен отозван; защищённая замена работает. Отдельный контрольный вариант с намеренной регрессией — учебное сравнение, а не развёрнутый сервис.

Объясните себе: какое событие обнаружило проблему, какая настройка вызвала её, почему одного исправления политики было недостаточно и как новое утверждение о кандидате предотвращает повторение. Проверка курса использует кандидата с реальной регрессией, подтверждает блокировку барьером и проверяет, что предыдущий безопасный работающий артефакт сохраняется. Документ исследования фиксированного формата не требуется.

Резюме

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