UI-тестирование является критически важным этапом обеспечения качества веб-приложений. Однако его безопасностный аспект часто остается в тени. Безопасное UI-тестирование подразумевает не только проверку функциональности, но и защиту от утечки конфиденциальных данных, учетных записей тестовых пользователей, а также обеспечение изоляции тестовой среды от продакшена. Данное руководство охватывает ключевые принципы и практики безопасного написания и выполнения UI-тестов с примерами на популярных фреймворках.
Принцип 1: Изоляция тестовых данных и учетных записей. Никогда не используйте реальные пользовательские данные, особенно персональные (PII) или платежные данные, в тестах. Создавайте изолированные тестовые учетные записи с помощью API вашего приложения или специальных seed-скриптов перед прогоном тестов. Убедитесь, что эти учетные записи имеют минимально необходимые права (принцип наименьших привилегий).
Пример на Puppeteer (Node.js): создание пользователя через бэкенд-API перед тестом.
const puppeteer = require('puppeteer');
const axios = require('axios');
const TEST_API = 'https://api-test.example.com';
const TEST_CREDENTIALS = { username: `testuser_${Date.now()}`, password: 'SecurePass123!' };
async function createTestUser() {
const response = await axios.post(`${TEST_API}/users/register`, TEST_CREDENTIALS);
return response.data.token; // Получаем токен для последующего входа
}
describe('Secure Login Test', () => {
let browser, page, authToken;
beforeAll(async () => {
authToken = await createTestUser(); // Создаем уникального пользователя
browser = await puppeteer.launch({ headless: 'new' });
page = await browser.newPage();
});
it('should log in with test credentials', async () => {
await page.goto('https://app-test.example.com/login');
await page.type('#username', TEST_CREDENTIALS.username);
await page.type('#password', TEST_CREDENTIALS.password);
await page.click('#submit');
await page.waitForNavigation();
// Проверка успешного входа
const url = await page.url();
expect(url).toContain('/dashboard');
});
afterAll(async () => {
// Опционально: удаление тестового пользователя через API
await axios.delete(`${TEST_API}/users/me`, { headers: { Authorization: `Bearer ${authToken}` } });
await browser.close();
});
});
Принцип 2: Безопасное хранение секретов. Ключи API, пароли тестовых аккаунтов, токены доступа не должны быть захардкожены в тестовом коде. Используйте переменные окружения или специализированные сервисы для управления секретами (HashiCorp Vault, AWS Secrets Manager). В CI/CD пайплайне настройте инъекцию этих секретов.
Пример использования dotenv в Node.js для Cypress:
// В файле cypress/plugins/index.js или cypress.config.js
require('dotenv').config();
module.exports = {
e2e: {
setupNodeEvents(on, config) {
config.env.testUserPassword = process.env.TEST_USER_PASSWORD;
return config;
},
},
};
// В тесте Cypress
it('logs in with env password', () => {
const username = 'test_user';
const password = Cypress.env('testUserPassword'); // Секрет из переменных окружения
cy.visit('/login');
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.get('form').submit();
cy.url().should('include', '/dashboard');
});
Принцип 3: Защита от межсайтовой подделки запросов (CSRF) и инъекций в тестах. Ваши UI-тесты должны проверять, что приложение корректно обрабатывает вредоносные данные. Напишите тесты, которые пытаются отправить скрипты через поля ввода (XSS) или подделанные CSRF-токены. Это не только проверяет безопасность приложения, но и гарантирует, что ваши тестовые сценарии сами не становятся вектором атаки при использовании реальных данных.
Пример проверки санитизации ввода с помощью Selenium WebDriver (Python):
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("http://test-app.example.com/comment")
# Попытка XSS-инъекции через UI
xss_payload = "alert('xss')"
comment_input = driver.find_element(By.ID, "commentText")
comment_input.send_keys(xss_payload)
driver.find_element(By.ID, "submitComment").click()
# Проверяем, что скрипт не исполнился (alert не появился).
# В идеале, на странице должен отображаться экранированный текст.
page_source = driver.page_source
assert "" not in page_source, "XSS vulnerability detected! Script tag found in page source."
assert "<script>" in page_source, "Input was not properly sanitized."
Принцип 4: Использование отдельной, изолированной тестовой среды. Тесты должны выполняться против staging или специальной test-среды, максимально похожей на прод, но полностью изолированной. Никогда не запускайте автоматические UI-тесты напрямую на продакшн-базе данных или продакшн-сервисах. Это может привести к изменению реальных данных, DoS-атаке на ваш же сервис или утечке информации.
Принцип 5: Безопасность самого тестового кода и инфраструктуры. Репозиторий с тестами должен быть защищен так же, как и основной код. Используйте code review для тестов. Убедитесь, что артефакты тестов (логи, скриншоты, видео) не содержат чувствительной информации. Настройте их очистку после анализа.
Интеграция с инструментами динамического анализа безопасности (DAST). Вы можете интегрировать выполнение UI-тестов с инструментами вроде OWASP ZAP, запуская их как прокси. Это позволяет автоматически обнаруживать уязвимости во время прохождения тестовых сценариев.
Безопасное UI-тестирование — это комплексный подход, который защищает и ваше приложение, и ваши данные на всех этапах тестового цикла. Следование этим принципам минимизирует риски и повышает общую надежность процесса разработки.
Безопасность UI-тестирования с примерами кода
Практическое руководство по обеспечению безопасности при написании и выполнении UI-тестов, включающее изоляцию данных, управление секретами, проверку на уязвимости и изоляцию среды с примерами кода для Puppeteer, Cypress и Selenium.
215
5
Комментарии (11)