آزمایش امنیتی SDET: قدرت ZAP در تست های خودکار

به عنوان مهندسین توسعه نرم افزار در تست (SDETS) ، ما برای اتوماسیون غریبه نیستیم. ما چارچوب هایی را برای اعتبار سنجی عملکرد ، عملکرد و قابلیت استفاده می سازیم. اما در چشم انداز تهدید امروز ، تست امنیتی دیگر نمی تواند یک نتیجه باشد – و این جایی است که OWASP ZAP (Zed Attack Proxy) می درخشد. بیایید بررسی کنیم که چرا ادغام ZAP در تست های خودکار شما اهمیت دارد و چگونه نقش شما در تأمین برنامه ها را تغییر می دهد.
چرا آزمایش امنیتی برای SDET اهمیت دارد
-
امنیت چپ چپ
آسیب پذیری های امنیتی در اواخر هزینه SDLC گرفتار شده است 6 برابر بیشتر برای رفع زودرس. SDET ها با ادغام آزمایش امنیتی در اتوماسیون ، کاهش خطر فعال را فعال می کنند.
-
فراتر از آزمایش عملکردی
SDET های مدرن نگهبان با کیفیت هستند وت امنیت یک ویژگی ممکن است کاملاً کار کند اما داده های حساس نشت یا نقاط تزریق SQL را در معرض نمایش قرار می دهد.
-
انطباق و شهرت
GDPR ، PCI-DSS و سایر مقررات نیاز به سخت گیری امنیت دارند. تست های امنیتی خودکار اثبات قابل شنیدن از دقت کافی را ارائه می دهد.
OWASP ZAP: چاقوی ارتش سوئیس امنیتی SDET
Zap فقط یک اسکنر دیگر نیست – ابزار ابزار توسعه دهنده محور طراحی شده برای اتوماسیون:
- اسکن منفعل: ترافیک را در طول آزمایشات عملکردی تجزیه و تحلیل کنید
- اسکن فعال: شبیه سازی حملات (XSS ، SQLI و غیره)
- طراحی اول: مناسب برای خطوط لوله CI/CD
- قابل تنظیم: افزودنی برای OAUTH ، GraphQL و موارد دیگر
ادغام ZAP در چارچوب خود: مزایای کلیدی
✅ اتوماسیون بدون درز
Trigger از طریق API REST ZAP در طول سوئیت های تست سلنیوم به صورت برنامه ای اسکن می کند.
✅ آزمایش آگاهانه
از جلسات معتبر از تست های عملکردی خود برای اسکن گردش کار پس از لگین استفاده کنید.
✅ CI/CD دوستانه
هنگامی که ZAP آسیب پذیری های پرخطر را تشخیص می دهد ، به طور خودکار ایجاد می شود.
✅ گزارش های آماده جذاب
گزارش های HTML/JSON ZAP را با تجزیه و تحلیل روند Allure برای معیارهای امنیتی ترکیب کنید.
نحوه ادغام ZAP با Selenium + testng
نمای کلی معماری
- ZAP Proxy Setup: مسیر ترافیک سلنیوم را از طریق ZAP مسیر دهید
- اسکن منفعل در طول آزمایشات: اجازه دهید ZAP ترافیک HTTP/S را تجزیه و تحلیل کند
- اسکن فعال پس از آزمون: حملات را بعد از گردش کار بحرانی تحریک کنید
- گزارش: نتایج صادرات به Allure
توجه: حالت بدون سر به مراحل اضافی نیاز دارد و برای آزمایش عادی ZAP GUI قبل از شروع آزمایش باید باز شود.
قطعه کد مثال (وابستگی ها)
org.seleniumhq.selenium
selenium-java
4.30.0
io.cucumber
cucumber-java
7.21.1
org.zaproxy
zap-clientapi
1.16.0
org.testng
testng
7.10.2
test
io.qameta.allure
allure-cucumber7-jvm
test
io.qameta.allure
allure-testng
2.29.1
پرونده
Feature: ZAP Security Check
@sec
Scenario: I need to run security check
When i started security test
تعریف مرحله
package com.velespit.step_definitions;
import com.velespit.utilities.BrowserUtils;
import com.velespit.utilities.ConfigurationReader;
import io.qameta.allure.Allure;
import io.qameta.allure.Description;
import io.qameta.allure.junit4.Tag;
import org.testng.annotations.Test;
import org.zaproxy.clientapi.core.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zaproxy.clientapi.core.ClientApi;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
public class ZapSecurityTest {
private static final Logger logger = LoggerFactory.getLogger(ZapSecurityTest.class);
private static final String ZAP_PROXY_HOST = "localhost";
private static final int ZAP_PROXY_PORT = 8080;
private static final String ZAP_API_KEY = ConfigurationReader.getProperty("zap_api_key"); // Replace with your ZAP API key
private static ClientApi zapClient;
public ZapSecurityTest() {
zapClient = new ClientApi(ZAP_PROXY_HOST, ZAP_PROXY_PORT, ZAP_API_KEY);
}
public static void startZAPHeadless() {
try {
ProcessBuilder processBuilder = new ProcessBuilder(
"cmd.exe", "/c", ConfigurationReader.getProperty("zap_path"), "-daemon", "-port", "8080", "-host", "localhost"
);
processBuilder.directory(new File(ConfigurationReader.getProperty("zap_path")));
processBuilder.redirectErrorStream(true);
Process zapProcess = processBuilder.start();
logger.info("ZAP started in headless mode.");
// Wait until ZAP is fully initialized before continuing
waitForZapStartup();
} catch (Exception e) {
logger.error("Failed to start ZAP in headless mode.", e);
}
}
private static void waitForZapStartup() throws InterruptedException {
logger.info("Waiting for ZAP to initialize...");
int retries = 10;
while (retries > 0) {
if (isZapRunning()) {
logger.info("ZAP is ready!");
return;
}
BrowserUtils.sleep(5); // Wait 5 seconds
retries--;
}
throw new RuntimeException("ZAP did not start within the expected time!");
}
private static boolean isZapRunning() {
try {
ProcessBuilder checkProcess = new ProcessBuilder("curl", "-s", "http://localhost:8080/");
Process process = checkProcess.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String response;
while ((response = reader.readLine()) != null) {
if (response.contains("ZAP")) {
return true;
}
}
} catch (Exception e) {
return false;
}
return false;
}
public void startZapSecurityTest(String targetUrl) {
try {
// Start a new session
zapClient.core.newSession("ZAP Security Test", "true");
// Spider the target URL to discover links
logger.info("Starting ZAP Spider for: {}", targetUrl);
ApiResponse spiderResponse = zapClient.spider.scan(targetUrl, null, null, null, null);
String scanId = ((ApiResponseElement) spiderResponse).getValue();
waitForSpiderToComplete(scanId);
// Active scan for vulnerabilities
logger.info("Starting ZAP Active Scan for: {}", targetUrl);
ApiResponse activeScanResponse = zapClient.ascan.scan(targetUrl, "true", "false", null, null, null);
String activeScanId = ((ApiResponseElement) activeScanResponse).getValue();
waitForActiveScanToComplete(activeScanId);
// Generate and report security findings
reportSecurityFindings(targetUrl);
} catch (ClientApiException | InterruptedException e) {
logger.error("An error occurred during ZAP security testing: ", e);
Allure.addAttachment("Error", "text/plain", "An error occurred: " + e.getMessage());
}
}
private void waitForSpiderToComplete(String scanId) throws ClientApiException, InterruptedException {
while (true) {
BrowserUtils.sleep(2); // Poll every 2 seconds
ApiResponse spiderStatus = zapClient.spider.status(scanId);
int progress = Integer.parseInt(((ApiResponseElement) spiderStatus).getValue());
logger.info("ZAP Spider progress: {}%", progress);
if (progress >= 100) {
break;
}
}
logger.info("ZAP Spider completed.");
}
private void waitForActiveScanToComplete(String scanId) throws ClientApiException, InterruptedException {
while (true) {
BrowserUtils.sleep(2); // Poll every 2 seconds
ApiResponse activeScanStatus = zapClient.ascan.status(scanId);
int progress = Integer.parseInt(((ApiResponseElement) activeScanStatus).getValue());
logger.info("ZAP Active Scan progress: {}%", progress);
if (progress >= 100) {
break;
}
}
logger.info("ZAP Active Scan completed.");
}
private void reportSecurityFindings(String targetUrl) throws ClientApiException {
// Get alerts (vulnerabilities) using the new API method
ApiResponse alertsResponse = zapClient.alert.alerts(targetUrl, null, null, null);
List<Map<String, String>> alerts = parseAlerts((ApiResponseList) alertsResponse);
if (alerts.isEmpty()) {
Allure.addAttachment("ZAP Security Result", "text/plain", "No security issues found for: " + targetUrl);
} else {
Allure.addAttachment("ZAP Security Result", "text/plain", "Security Issues Found for: " + targetUrl);
for (Map<String, String> alert : alerts) {
String alertDetails = formatAlertDetails(alert);
if (alertDetails != null) {
Allure.addAttachment("Alert: " + alert.get("alert"), "text/plain", alertDetails);
}
}
}
}
private List<Map<String, String>> parseAlerts(ApiResponseList alertsResponse) {
List<Map<String, String>> alerts = new ArrayList<>();
for (ApiResponse response : alertsResponse.getItems()) {
if (response instanceof ApiResponseSet alertSet) {
if (alertSet.getValuesMap() != null && !alertSet.getValuesMap().isEmpty()) {
Map<String, String> alertDetails = new HashMap<>();
for (Map.Entry<String, ApiResponse> entry : alertSet.getValuesMap().entrySet()) {
if (entry.getValue() != null) {
alertDetails.put(entry.getKey(), entry.getValue().toString());
} else {
alertDetails.put(entry.getKey(), "null"); // null kontrolü
}
}
alerts.add(alertDetails);
}
}
}
return alerts;
}
private String formatAlertDetails(Map<String, String> alert) {
if (alert == null || alert.isEmpty()) {
return null; // Return null if map is empty or null
}
String risk = alert.get("risk");
if (risk == null || risk.equals("Low") || risk.equals("Informational")) {
return null; // Return null if low or informational risk
}
// Check if necessary alert keys are available
if (!alert.containsKey("alert") || !alert.containsKey("confidence") ||
!alert.containsKey("description") || !alert.containsKey("solution") ||
!alert.containsKey("reference") || !alert.containsKey("url")) {
return "Missing required alert details."; // Return error message if missing information
}
return "Alert: " + alert.get("alert") + "\n" +
"Risk: " + risk + "\n" +
"Confidence: " + alert.get("confidence") + "\n" +
"Description: " + alert.get("description") + "\n" +
"Solution: " + alert.get("solution") + "\n" +
"Reference: " + alert.get("reference") + "\n" +
"URL: " + alert.get("url") + "\n" +
"--------------------";
}
public static void shutDownZAP() {
// Shutdown ZAP after testing
try {
zapClient.core.shutdown();
logger.info("ZAP has been shut down.");
} catch (ClientApiException e) {
logger.error("Failed to shutdown ZAP.", e);
}
}
@Tag("Security")
@Description("Security Test with ZAP API using TestNG")
@Test
public void secTest() {
startZAPHeadless();
startZapSecurityTest("https://yusufasik.com");
shutDownZAP();
}
چالش ها و بهترین شیوه ها
⚠ مشکلات مشترک
-
مثبت کاذب: همیشه نتایج سه گانه
-
عمل: برنامه های اسکن های تهاجمی را از اوج خود برنامه ریزی کنید
-
رسیدگی به جلسه: استفاده مجدد از زمینه های معتبر
🔑 نکات طرفدار
-
برای جلوگیری از پوسته پوسته شدن با اسکن منفعل شروع کنید
-
برای فیلتر کردن آسیب پذیری های بی ربط از Zap's tags استفاده کنید (یا بیانیه من اگر نمی خواهید با آن مقابله کنید)
-
ZAP Weekly را به روز کنید – آسیب پذیری های جدید به طور مداوم ظهور می کنند
نتیجه گیری: امنیت است شما مسئولیت اکنون
SDET ها منحصر به فرد برای دموکراتیک کردن آزمایش های امنیتی قرار دارند. با تعبیه ZAP در چارچوب اتوماسیون خود ، شما:
-
آسیب پذیری ها را بگیرید قبل از رسیدن به تولید
-
امنیت را در گردش کار روزانه تیم ایجاد کنید
-
نقش خود را از نویسنده تست به معمار با کیفیت بالا ببرید
آماده امتحان آن هستید؟ سوالات ZAP خود را در زیر رها کنید یا نحوه تست امنیتی یکپارچه را به اشتراک بگذارید! 👇