Тестирование безопасности — это критически важный аспект обеспечения качества, который гарантирует, что приложения защищены от вредоносных атак и несанкционированного доступа. OWASP (как обсуждается в Penetration Testing Basics for QA Testers) (Open Web Application Security Project) Top 10 представляет наиболее критичные риски безопасности для веб-приложений, обеспечивая основу для специалистов по QA для построения комплексных стратегий тестирования безопасности.
Это руководство исследует каждую уязвимость OWASP (как обсуждается в Security Testing for QA: A Practical Guide) Top 10, практические подходы к тестированию, инструменты для обнаружения и лучшие практики по выявлению и устранению рисков безопасности в современных приложениях.
Понимание OWASP Top 10
OWASP Top 10 — это регулярно обновляемый отчет, описывающий десять наиболее критичных рисков безопасности, с которыми сталкиваются веб-приложения. Для специалистов QA понимание этих уязвимостей необходимо для:
- Оценки Рисков: Раннее выявление потенциальных слабостей безопасности
- Планирования Тестов: Включение тест-кейсов безопасности в процессы QA
- Сотрудничества: Коммуникации проблем безопасности с разработчиками
- Соответствия: Соблюдения стандартов и регуляций безопасности
- Защиты Пользователей: Защиты конфиденциальных пользовательских данных и приватности
OWASP (как обсуждается в OWASP ZAP Automation: Security Scanning in CI/CD) Top 10 (Издание 2021)
Ранг | Уязвимость | Влияние | Распространенность |
---|---|---|---|
A01 | Сломанный Контроль Доступа | Высокое | Очень Часто |
A02 | Криптографические Сбои | Высокое | Часто |
A03 | Инъекция | Критическое | Часто |
A04 | Небезопасный Дизайн | Высокое | Часто |
A05 | Неправильная Конфигурация Безопасности | Среднее | Очень Часто |
A06 | Уязвимые и Устаревшие Компоненты | Высокое | Часто |
A07 | Сбои Идентификации и Аутентификации | Высокое | Часто |
A08 | Сбои Целостности ПО и Данных | Высокое | Реже |
A09 | Сбои Логирования и Мониторинга Безопасности | Среднее | Часто |
A10 | Подделка Запросов на Стороне Сервера (SSRF) | Среднее | Реже |
A01: Сломанный Контроль Доступа
Контроль доступа применяет политики, предотвращающие действия пользователей за пределами их предполагаемых разрешений. Сломанный контроль доступа позволяет атакующим получать доступ к несанкционированным функциям или данным.
Распространенные Уязвимости Контроля Доступа
Вертикальная Эскалация Привилегий:
# Обычный пользователь получает доступ к функциям администратора
GET /admin/users HTTP/1.1
Authorization: Bearer regular_user_token
Горизонтальная Эскалация Привилегий:
# Пользователь получает доступ к данным другого пользователя
GET /api/users/123/profile HTTP/1.1
# Должен получать доступ только к своему профилю (user ID 456)
Небезопасные Прямые Ссылки на Объекты (IDOR):
// Предсказуемые ID ресурсов
/documents/1001
/documents/1002 // Может ли пользователь получить к этому доступ?
/documents/1003
Подходы к Тестированию
Ручное Тестирование:
- Попытка доступа к ограниченным URL напрямую
- Изменение параметров URL (ID, имена пользователей)
- Тестирование различных ролей и разрешений пользователей
- Проверка отсутствующего контроля доступа на уровне функций
- Проверка ограничений POST/PUT/DELETE
Автоматизированное Тестирование:
# Пример: Тестирование уязвимости IDOR
def test_idor_vulnerability():
# Логин как пользователь A
user_a_token = login("userA", "password")
user_a_id = get_user_id(user_a_token)
# Логин как пользователь B
user_b_token = login("userB", "password")
user_b_id = get_user_id(user_b_token)
# Попытка доступа к ресурсам пользователя B с токеном пользователя A
response = requests.get(
f"/api/users/{user_b_id}/profile",
headers={"Authorization": f"Bearer {user_a_token}"}
)
# Должно вернуть 403 Forbidden
assert response.status_code == 403, "Обнаружена уязвимость IDOR!"
Лучшие Практики Предотвращения
- Реализовать контроль доступа на основе ролей (RBAC)
- Запрещать доступ по умолчанию (подход белого списка)
- Использовать косвенные ссылки на объекты (UUID вместо последовательных ID)
- Логировать сбои контроля доступа
- Ограничивать скорость API запросов
A02: Криптографические Сбои
Криптографические сбои возникают, когда конфиденциальные данные неправильно защищены шифрованием, что приводит к раскрытию паролей, номеров кредитных карт, медицинских записей и другой конфиденциальной информации.
Распространенные Криптографические Проблемы
Слабые Алгоритмы Шифрования:
# Небезопасно - MD5 криптографически сломан
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()
# Безопасно - Использовать bcrypt или Argon2
import bcrypt
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
Незашифрованная Передача Данных:
# Небезопасно - HTTP передает данные открытым текстом
http://example.com/login
# Безопасно - HTTPS шифрует данные при передаче
https://example.com/login
Жестко Закодированные Секреты:
// НИКОГДА не делайте это!
const API_KEY = "sk_live_abc123xyz789";
const DB_PASSWORD = "admin123";
// Используйте переменные окружения
const API_KEY = process.env.API_KEY;
const DB_PASSWORD = process.env.DB_PASSWORD;
Подходы к Тестированию
Тестирование Конфигурации SSL/TLS:
# Проверка валидности SSL сертификата
openssl s_client -connect example.com:443
# Тест на слабые шифры
nmap --script ssl-enum-ciphers -p 443 example.com
# Проверка поддержки версии TLS
testssl.sh https://example.com
Тестирование Раскрытия Конфиденциальных Данных:
- Инспектирование сетевого трафика на незашифрованные конфиденциальные данные
- Проверка хранилища браузера (localStorage, sessionStorage, cookies)
- Просмотр сообщений об ошибках на раскрытие информации
- Тестирование механизмов хранения паролей
- Проверка secure флага на cookies
Чеклист Тестирования:
криптографическое_тестирование:
данные_в_покое:
- Шифрование базы данных включено
- Зашифрованное хранилище файлов
- Безопасное управление ключами
данные_в_транзите:
- HTTPS принудительно (HSTS включен)
- Сильная конфигурация TLS (TLS 1.2+)
- Валидные SSL сертификаты
конфиденциальные_данные:
- Пароли хешированы сильным алгоритмом
- Кредитные карты токенизированы
- PII зашифрованы
- Нет конфиденциальных данных в URL или логах
A03: Инъекция
Недостатки инъекции возникают, когда недоверенные данные отправляются интерпретатору как часть команды или запроса. SQL, NoSQL, команды ОС и LDAP инъекции — распространенные варианты.
SQL Инъекция
Уязвимый Код:
# Опасно - уязвимо к SQL инъекции
username = request.POST['username']
password = request.POST['password']
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)
Пример Атаки:
-- Ввод атакующего для username: admin' OR '1'='1
-- Результирующий запрос обходит аутентификацию:
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = 'anything'
Безопасный Код:
# Безопасно - использование параметризованных запросов
query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
Тестирование SQL Инъекции
Payload’ы Ручного Тестирования:
-- Базовые тесты
' OR '1'='1
'; DROP TABLE users; --
' UNION SELECT NULL, NULL, NULL--
-- Слепая инъекция на основе времени
'; WAITFOR DELAY '00:00:05'--
-- Слепая инъекция на основе булевых значений
' AND 1=1--
' AND 1=2--
Автоматизированное Тестирование:
# Пример SQLMap
sqlmap -u "http://example.com/product?id=1" --batch --dbs
# Тестирование с OWASP ZAP
from zapv2 import ZAPv2
zap = ZAPv2(proxies={'http': 'http://127.0.0.1:8080'})
zap.ascan.scan(target_url)
Инъекция Команд
Уязвимый Код:
# Опасно - уязвимо к инъекции команд
filename = request.GET['file']
os.system(f'cat {filename}')
Пример Атаки:
# Ввод атакующего: report.txt; rm -rf /
# Выполняемая команда: cat report.txt; rm -rf /
Безопасный Код:
# Безопасно - валидация ввода и экранирование
import subprocess
import shlex
filename = request.GET['file']
# Валидировать имя файла
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', filename):
raise ValueError("Неверное имя файла")
# Использовать subprocess с аргументами списка
subprocess.run(['cat', filename], check=True)
NoSQL Инъекция
Уязвимый Код:
// Опасный MongoDB запрос
const username = req.body.username;
const password = req.body.password;
db.users.find({
username: username,
password: password
});
Пример Атаки:
{
"username": {"$ne": null},
"password": {"$ne": null}
}
Безопасный Код:
// Безопасно - валидация и санитизация ввода
const username = String(req.body.username);
const password = String(req.body.password);
db.users.findOne({
username: username,
password: hashPassword(password)
});
A04: Небезопасный Дизайн
Небезопасный дизайн представляет отсутствующие или неэффективные контроли безопасности из-за ошибочных решений архитектуры и дизайна. Это отличается от небезопасной реализации.
Недостатки Дизайна для Тестирования
Отсутствующее Ограничение Скорости:
# Тест уязвимости к брутфорсу
def test_login_rate_limiting():
for i in range(1000):
response = requests.post("/login", data={
"username": "admin",
"password": f"password{i}"
})
# Должно реализовать ограничение скорости после N попыток
if i > 5:
assert response.status_code == 429, "Ограничение скорости не обнаружено!"
Недостатки Бизнес-Логики:
# Пример: Эксплойт отрицательного количества
def test_negative_quantity_vulnerability():
# Добавить товар с отрицательным количеством
response = requests.post("/cart/add", json={
"product_id": 123,
"quantity": -10,
"price": 100
})
# Проверить, рассчитывается ли отрицательная сумма (кредитуя пользователя)
cart_total = get_cart_total()
assert cart_total >= 0, "Эксплойт отрицательного количества возможен!"
Недостаточная Валидация:
// Проверка отсутствующих бизнес-правил
test('невозможно перевести больше баланса счета', async () => {
const transfer = {
from: 'account123',
to: 'account456',
amount: 999999 // Больше баланса
};
const response = await api.post('/transfer', transfer);
expect(response.status).toBe(400);
});
A05: Неправильная Конфигурация Безопасности
Неправильная конфигурация безопасности возникает, когда настройки безопасности не определены, реализованы или поддерживаются должным образом.
Распространенные Неправильные Конфигурации
Дефолтные Учетные Данные:
# Тест дефолтных учетных данных
common_defaults = [
("admin", "admin"),
("administrator", "password"),
("root", "root"),
("admin", "password123")
]
for username, password in common_defaults:
test_login(username, password)
Включенные Ненужные Функции:
# Тест включенных HTTP методов
OPTIONS /api/users HTTP/1.1
# Ответ должен ограничивать методы
Allow: GET, POST, DELETE # PUT/PATCH отключены?
Подробные Сообщения об Ошибках:
# Плохо - раскрывает внутренние детали
try:
db.query(sql)
except Exception as e:
return f"Ошибка базы данных: {str(e)}" # Раскрывает структуру БД
# Хорошо - общее сообщение об ошибке
try:
db.query(sql)
except Exception as e:
logger.error(f"Ошибка базы данных: {e}")
return "Произошла ошибка. Пожалуйста, попробуйте снова."
Листинг Директорий:
# Тест traversal директорий
curl http://example.com/uploads/
curl http://example.com/../../../etc/passwd
Тестирование Заголовков Безопасности
def test_security_headers():
response = requests.get("https://example.com")
headers = response.headers
# Требуемые заголовки безопасности
assert 'X-Content-Type-Options' in headers
assert headers['X-Content-Type-Options'] == 'nosniff'
assert 'X-Frame-Options' in headers
assert headers['X-Frame-Options'] in ['DENY', 'SAMEORIGIN']
assert 'Strict-Transport-Security' in headers
assert 'Content-Security-Policy' in headers
# Не должно раскрывать информацию о сервере
assert 'Server' not in headers or 'nginx' not in headers.get('Server', '').lower()
A06: Уязвимые и Устаревшие Компоненты
Использование компонентов с известными уязвимостями (библиотеки, фреймворки, ПО) может скомпрометировать безопасность приложения.
Сканирование Зависимостей
NPM Audit:
# Проверка уязвимых npm пакетов
npm audit
# Автоматическое исправление уязвимостей
npm audit fix
# Генерация детального отчета
npm audit --json > audit-report.json
Требования Python:
# Проверка Python зависимостей
pip install safety
safety check
# Сканирование файла requirements
safety check -r requirements.txt
Dependency-Check (OWASP):
# Сканирование Java/JavaScript/Python проектов
dependency-check --project "MyApp" --scan ./ --format HTML
Процесс Тестирования
тестирование_зависимостей:
автоматизированное_сканирование:
- npm_audit: "Ежедневно в CI/CD"
- snyk: "Еженедельное полное сканирование"
- dependabot: "Автоматический PR для обновлений"
ручной_обзор:
- база_данных_cve: "Проверить CVE для критичных компонентов"
- проверка_версии: "Обеспечить последние стабильные версии"
- проверка_eol: "Определить компоненты окончания срока"
устранение:
- обновить_зависимости: "Применить патчи безопасности"
- удалить_неиспользуемые: "Удалить неиспользуемые библиотеки"
- найти_альтернативы: "Заменить уязвимые компоненты"
A07: Сбои Идентификации и Аутентификации
Механизмы аутентификации часто реализованы неправильно, позволяя атакующим скомпрометировать пароли, ключи или токены сессий.
Тестирование Аутентификации
Credential Stuffing:
# Тест механизма блокировки аккаунта
def test_account_lockout():
failed_attempts = 0
for i in range(10):
response = login("user@example.com", f"wrong_password_{i}")
if response.status_code == 401:
failed_attempts += 1
# Аккаунт должен блокироваться после N попыток
if failed_attempts >= 5:
assert "account locked" in response.text.lower()
Управление Сессиями:
def test_session_fixation():
# Получить сессию перед логином
response1 = requests.get("https://example.com")
session_before = response1.cookies.get('sessionid')
# Логин
response2 = requests.post("https://example.com/login",
cookies={'sessionid': session_before},
data={"username": "user", "password": "pass"})
# Сессия должна измениться после аутентификации
session_after = response2.cookies.get('sessionid')
assert session_before != session_after, "Уязвимость фиксации сессии!"
Слабая Политика Паролей:
weak_passwords = [
"123456",
"password",
"admin",
"user123",
"qwerty"
]
for pwd in weak_passwords:
response = register_user("test@example.com", pwd)
assert response.status_code == 400, f"Слабый пароль принят: {pwd}"
Тестирование Многофакторной Аутентификации
def test_mfa_bypass():
# Логин с валидными учетными данными
response = login("user@example.com", "ValidPassword123!")
# Проверить, принудительно ли MFA
assert "mfa_required" in response.json() or response.status_code == 401
# Попытка доступа к защищенному ресурсу без MFA
response = requests.get("/api/sensitive-data",
headers={"Authorization": f"Bearer {partial_token}"})
# Должно быть отклонено без завершения MFA
assert response.status_code == 403
A08: Сбои Целостности ПО и Данных
Эта категория фокусируется на коде и инфраструктуре, которые не защищают от нарушений целостности, таких как небезопасные CI/CD пайплайны или автообновления без верификации.
Тестирование Проблем Целостности
Неподписанные Обновления:
def test_update_signature_verification():
# Загрузить пакет обновления
update_package = download_update("https://cdn.example.com/update.zip")
# Проверить цифровую подпись
signature = download_signature("https://cdn.example.com/update.zip.sig")
# Должно верифицировать перед установкой
assert verify_signature(update_package, signature), "Обновление не подписано!"
Уязвимости Десериализации:
# Тест небезопасной десериализации
import pickle
import base64
# Вредоносный payload
malicious_data = base64.b64encode(pickle.dumps(malicious_object))
response = requests.post("/api/process",
data={"data": malicious_data})
# Должно отклонять ненадежную десериализацию
assert response.status_code == 400
Безопасность CI/CD Пайплайна:
чеклист_безопасности_ci_cd:
целостность_пайплайна:
- "✓ Требуются подписанные коммиты"
- "✓ Защищенные ветки принудительно"
- "✓ Code review обязателен"
- "✓ Сканирования безопасности в пайплайне"
целостность_артефактов:
- "✓ Артефакты сборки подписаны"
- "✓ Верификация контрольной суммы"
- "✓ Отслеживание происхождения"
- "✓ Неизменяемое хранилище артефактов"
A09: Сбои Логирования и Мониторинга Безопасности
Недостаточное логирование и мониторинг позволяют атакующим сохранять присутствие, переходить к другим системам и подменять данные без обнаружения.
Тестирование Требований к Логированию
Критические События для Логирования:
critical_events = [
"попытки_логина",
"неудачная_аутентификация",
"сбои_контроля_доступа",
"сбои_валидации_ввода",
"попытки_эскалации_привилегий",
"операции_администратора",
"изменения_данных",
"криптографические_сбои"
]
def test_logging_coverage():
for event_type in critical_events:
trigger_event(event_type)
# Проверить, логируется ли событие
logs = get_application_logs()
assert any(event_type in log for log in logs),
f"Событие не логировано: {event_type}"
Верификация Содержимого Логов:
def test_log_content_quality():
# Запустить подозрительную активность
failed_login("admin", "wrong_password", ip="192.168.1.100")
# Получить запись лога
log_entry = get_latest_log()
# Верифицировать, что существенная информация захвачена
assert "username" in log_entry # Кто
assert "ip_address" in log_entry # Откуда
assert "timestamp" in log_entry # Когда
assert "action" in log_entry # Что
assert "result" in log_entry # Результат
# Обеспечить, что конфиденциальные данные не логируются
assert "password" not in log_entry
A10: Подделка Запросов на Стороне Сервера (SSRF)
Недостатки SSRF возникают, когда веб-приложение получает удаленный ресурс без валидации предоставленного пользователем URL, позволяя атакующим принудить приложение отправлять запросы к неожиданным местам назначения.
Тестирование SSRF
Базовое Обнаружение SSRF:
def test_ssrf_vulnerability():
# Попытка доступа к внутренним ресурсам
internal_urls = [
"http://localhost/admin",
"http://127.0.0.1:8080/status",
"http://169.254.169.254/latest/meta-data/", # метаданные AWS
"http://internal-service:3000/api"
]
for url in internal_urls:
response = requests.post("/api/fetch", json={"url": url})
# Должно блокировать внутренние URL
assert response.status_code in [400, 403], f"SSRF возможно: {url}"
Доступ к Метаданным Облака:
# Тест доступа к метаданным AWS (распространенная цель SSRF)
def test_cloud_metadata_ssrf():
aws_metadata_url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
response = requests.post("/api/fetch-url",
json={"url": aws_metadata_url})
# Не должно раскрывать облачные учетные данные
assert "AWS" not in response.text
assert "AccessKeyId" not in response.text
Инструменты Тестирования Безопасности
Инструмент | Категория | Лучше Для | Стоимость |
---|---|---|---|
OWASP ZAP | Динамическое Тестирование | Автоматизированное сканирование уязвимостей | Бесплатно |
Burp Suite | Прокси/Сканер | Ручное тестирование безопасности | Бесплатно/Платно |
Nikto | Web Scanner | Сканирование уязвимостей сервера | Бесплатно |
SQLMap | Инъекция | Обнаружение SQL инъекции | Бесплатно |
Nmap | Network Scanner | Обнаружение портов и сервисов | Бесплатно |
Snyk | Сканирование Зависимостей | Обнаружение уязвимых компонентов | Бесплатно/Платно |
SonarQube | Статический Анализ | Качество и безопасность кода | Бесплатно/Платно |
Acunetix | Web Scanner | Комплексное сканирование веб-уязвимостей | Платно |
Nessus | Vulnerability Scanner | Сканирование инфраструктуры | Платно |
Пример Интеграции Инструментов
# CI/CD Пайплайн Безопасности
security_pipeline:
pre_commit:
- git_secrets: "Сканирование жестко закодированных секретов"
- pre_commit_hooks: "Security linting"
build:
- sonarqube: "SAST анализ"
- dependency_check: "Уязвимые компоненты"
- container_scan: "Уязвимости Docker образа"
test:
- owasp_zap: "DAST сканирование"
- security_regression_tests: "Автоматизированные тесты безопасности"
pre_production:
- penetration_test: "Ручная оценка безопасности"
- security_review: "Обзор архитектуры"
Лучшие Практики для QA Тестирования Безопасности
1. Интегрировать Безопасность Рано (Shift Left)
- Включать требования безопасности в пользовательские истории
- Проводить моделирование угроз на фазе дизайна
- Проводить обзоры кода безопасности
- Запускать автоматизированные сканирования безопасности в CI/CD
2. Поддерживать Тест-Кейсы Безопасности
# Пример: Тест-кейс безопасности в Gherkin
Feature: Безопасность Аутентификации
Scenario: Блокировка аккаунта после неудачных попыток
Given зарегистрированный аккаунт пользователя
When я пытаюсь войти с неправильным паролем 5 раз
Then аккаунт должен быть заблокирован на 30 минут
And я должен получить email уведомление о блокировке
Scenario: Таймаут сессии
Given я залогинен
When я остаюсь неактивным 30 минут
Then моя сессия должна истечь
And я должен быть перенаправлен на страницу логина
3. Чеклист Тестирования Безопасности
## Чеклист Безопасности Перед Релизом
### Аутентификация и Авторизация
- [ ] Принудительная сложность пароля
- [ ] Реализована блокировка аккаунта
- [ ] MFA доступна для чувствительных действий
- [ ] Настроен таймаут сессии
- [ ] Правильно применен контроль доступа
### Защита Данных
- [ ] Конфиденциальные данные зашифрованы в покое
- [ ] HTTPS принудительно (HSTS включен)
- [ ] Настроены безопасные cookies
- [ ] Нет конфиденциальных данных в логах/URL
### Валидация Ввода
- [ ] Верифицирована защита от SQL инъекции
- [ ] Реализована защита XSS
- [ ] Присутствуют CSRF токены
- [ ] Принудительные ограничения загрузки файлов
### Конфигурация
- [ ] Изменены дефолтные учетные данные
- [ ] Отключены ненужные функции
- [ ] Настроены заголовки безопасности
- [ ] Обработка ошибок не раскрывает инфо
### Зависимости
- [ ] Все компоненты обновлены
- [ ] Нет известных уязвимостей
- [ ] Удалены неиспользуемые библиотеки
- [ ] Верифицировано соответствие лицензии
4. Непрерывный Мониторинг
- Настроить оповещения безопасности в production
- Мониторить необычные паттерны
- Отслеживать сбои аутентификации
- Регулярно просматривать логи безопасности
5. Сотрудничать с Командой Безопасности
- Участвовать в сессиях моделирования угроз
- Делиться находками QA с командой безопасности
- Учиться на результатах тестов на проникновение
- Оставаться в курсе новых угроз
Заключение
Тестирование безопасности — это существенная обязанность для современных специалистов QA. Понимание OWASP Top 10 обеспечивает прочную основу для выявления и предотвращения критических уязвимостей. Интегрируя тестирование безопасности на протяжении жизненного цикла разработки, используя соответствующие инструменты и следуя лучшим практикам, команды QA могут значительно снизить риски безопасности и защитить как пользователей, так и организации.
Ключевые выводы:
- Понимать каждую категорию уязвимости OWASP Top 10 и подход к тестированию
- Интегрировать автоматизированное сканирование безопасности в CI/CD пайплайны
- Поддерживать всесторонние тест-кейсы безопасности и чеклисты
- Использовать комбинацию ручных и автоматизированных техник тестирования
- Оставаться в курсе новых уязвимостей и векторов атак
- Тесно сотрудничать с командами разработки и безопасности
Помните, что безопасность — это не разовая активность, а непрерывный процесс, требующий бдительности, постоянного обучения и проактивного тестирования на протяжении всего жизненного цикла приложения.