İçeriğe geç
KURUMSAL Kurumsal teknoloji · İşletmenize özel mühendislik Kurumsal Yazılım · Yönetilen Sunucular · Kurumsal E-posta · LiteSpeed + CloudLinux · Imunify360 Güvenlik · cPanel Yönetim · Uygun pakette 3 Gbps'ye kadar ağ profili
AIOR

OWASP ZAP Kullanımı: Aktif, Kimlik Doğrulamalı ve API Güvenlik Taraması

  • Konu başlatıcısı Konu başlatıcısı Aior
  • Başlangıç tarihi Başlangıç tarihi

Aior

Administrator

Yetkili üye
Katıldı
2 Nis 2023
Mesajlar
929
Tepki puanı
2
Puan
18
Yaş
41
Konum
Turkey
Web sitesi
aior.com
Konu sahibi

Bu rehber neyi kapsıyor?​

ZAP, web uygulamalarını çalışırken dışarıdan test eden açık kaynaklı bir dinamik uygulama güvenliği testi (DAST) aracıdır. Uzun yıllar OWASP'ın amiral gemisi projelerinden biri olduğu için hâlâ en çok "OWASP ZAP" adıyla aranıyor. Proje Ağustos 2023'te OWASP'tan ayrılıp Linux Foundation bünyesindeki Software Security Project'e katıldı; Eylül 2024'ten bu yana "ZAP by Checkmarx" adıyla, yine Apache 2.0 lisanslı açık kaynak olarak geliştiriliyor.

OWASP Top 10:2025 kategorilerini ve CI'da pasif baseline taramasını pratik web güvenliği rehberimizde anlattık. Bu yazı oradan devam ediyor: saldırı yükü gönderen aktif tarama (active scan), giriş yapmış kullanıcıyla kimlik doğrulamalı tarama (authenticated scan), OpenAPI ve GraphQL taraması, Automation Framework ile tekrarlanabilir bir tarama planı ve sonuçların ayıklanması. Komutlar ZAP 2.17.0 (Aralık 2025) ve resmî Docker imajlarının belgeleriyle karşılaştırıldı; seçenekler sürümden sürüme değişebildiği için kendi sürümünüzde -h çıktısını kontrol edin.

Taramadan önce: izin, kapsam ve ortam​

Aktif tarama gerçek saldırı denemeleri gönderir: form alanlarına SQL enjeksiyonu yükleri yazar, parametrelerde betik enjeksiyonu dener, kısa sürede binlerce istek üretir. Bu yüzden şu üç kuraldan taviz verilmez:
  • Yazılı izin. Size ait olmayan ya da test için açıkça yetki verilmemiş bir sistemde aktif tarama çalıştırmak suç oluşturabilir. Türkiye'de bu tür eylemler TCK 243 (bilişim sistemine girme) ve 244 (sistemi engelleme, bozma, verileri yok etme veya değiştirme) kapsamında değerlendirilebilir. Barındırma, CDN ve WAF sağlayıcınızın kullanım koşullarına da bakın.
  • Canlı değil, test ortamı. Aktif tarama yorum, sipariş ve destek talebi gibi kayıtlar oluşturabilir, e-posta tetikleyebilir, hatta veri silebilir. Canlıya benzeyen ama anonimleştirilmiş veriyle çalışan bir staging ortamı kullanın ve taramadan önce yedek alın.
  • Haberdar bir ekip. Operasyon ekibine tarama penceresini ve kaynak IP adresini bildirin. WAF'ı tümden kapatmak yerine tarama yapan makinenin IP adresini izin listesine alın; aksi hâlde WAF'ın engellediği istekleri temiz sonuç sanırsınız.
Kapsamı da yazıya dökün: hangi alan adları, hangi yollar, hangi kullanıcı rolleri. Çıkış (logout), hesap silme, ödeme ve toplu e-posta gönderen uç noktaları kapsam dışı bırakın. Dışarıdan bir ekiple yapılan sızma testine hazırlığı pentest süreci yazımızda ayrıca ele aldık.

Üç hazır betik: baseline, full ve API​

ZAP'ın Docker imajları (ghcr.io/zaproxy/zaproxy:stable ya da Docker Hub'daki zaproxy/zap-stable) üç hazır tarama betiğiyle gelir; CI için tasarlanan küçük "bare" imajında bu betikler yoktur.
BetikNe yaparSaldırı gönderir mi?Nerede kullanılır
zap-baseline.pyVarsayılan olarak 1 dakika örümcek (spider), ardından yalnızca pasif kurallarHayırHer PR, canlı ortamın hafif kontrolü
zap-full-scan.pySüre sınırı olmadan örümcek, isteğe bağlı AJAX ya da istemci örümceği, ardından tam aktif taramaEvetGece çalışan staging taraması
zap-api-scan.pyOpenAPI, SOAP veya GraphQL tanımını içe aktarır, API'lere göre ayarlanmış aktif tarama yaparEvet (-S ile yalnızca baseline)Sürüm öncesi API kontrolü
Üçünün çıkış kodları aynıdır: 0 temiz, 1 en az bir FAIL, 2 yalnızca WARN, 3 başka bir hata. Varsayılan olarak her uyarı WARN sayılır; -g ile ürettiğiniz kural dosyasında kuralları FAIL ya da IGNORE yaparsınız. Full ve API taramalarının kural dosyası aktif kuralları da içerir ve IGNORE yapılan aktif kurallar hiç çalıştırılmaz; bu da taramayı hızlandırır.
Bash:
# İlk çalıştırma: tüm kuralların WARN olduğu şablonu üret (-g)
docker run --rm -v "$(pwd):/zap/wrk/:rw" -t ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py -t https://staging.example.com -m 10 -g full-rules.conf -r full-report.html

# Sonraki çalıştırmalar: düzenlenmiş kural dosyası, AJAX örümceği, HTML ve JSON rapor
docker run --rm -v "$(pwd):/zap/wrk/:rw" -t ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py -t https://staging.example.com -m 10 -j -T 30 \
  -c full-rules.conf -r full-report.html -J full-report.json
-m 10 örümceği 10 dakikayla sınırlar; full scan'de varsayılan süre sınırsızdır. -j, JavaScript ile oluşturulan sayfalar için klasik örümceğe ek olarak AJAX örümceğini çalıştırır; yeni sürümlerde --client-spider ile onun yerine istemci örümceği (client spider) seçilebilir. -T 30, ZAP'ın açılması ve pasif taramanın bitmesi için en fazla 30 dakika bekler. Raporlar bağlanan dizine, yani komutu çalıştırdığınız klasöre yazılır.

Automation Framework ile tek dosyada tarama planı​

Hazır betikler hızlı başlangıç için iyidir. Kimlik doğrulama, birden fazla örümcek, tarama politikası ve farklı rapor biçimleri devreye girince ZAP ekibinin önerdiği yol Automation Framework'tür: tüm akış tek bir YAML planında durur, plan Git'te sürümlenir ve herkes aynı taramayı çalıştırır. Plan iki bölümden oluşur: hedefi, kimlik doğrulamayı ve kullanıcıları tanımlayan env ile sırayla çalışan jobs.
YAML:
env:
  contexts:
    - name: staging
      urls:
        - https://staging.example.com
      includePaths:
        - "https://staging.example.com.*"
      excludePaths:
        - ".*/logout.*"
        - ".*/account/delete.*"
        - ".*/checkout/pay.*"
      authentication:
        method: browser
        parameters:
          loginPageUrl: https://staging.example.com/login
        verification:
          method: autodetect
      sessionManagement:
        method: autodetect
      users:
        - name: tester
          credentials:
            username: ${ZAP_USER}
            password: ${ZAP_PASS}
  parameters:
    failOnError: true
    failOnWarning: false
    progressToStdout: true
jobs:
  - type: alertFilter
    alertFilters:
      - ruleId: 10096
        newRisk: "False Positive"
        url: "https://staging.example.com/assets/.*"
        urlRegex: true
  - type: spider
    parameters:
      context: staging
      user: tester
      maxDuration: 10
  - type: spiderAjax
    parameters:
      context: staging
      user: tester
      maxDuration: 10
  - type: passiveScan-wait
    parameters:
      maxDuration: 10
  - type: activeScan
    parameters:
      context: staging
      user: tester
      maxScanDurationInMins: 90
      maxRuleDurationInMins: 10
      delayInMs: 50
      threadPerHost: 4
    policyDefinition:
      defaultStrength: Medium
      defaultThreshold: Medium
  - type: report
    parameters:
      template: traditional-html
      reportDir: /zap/wrk/reports
      reportFile: zap-nightly.html
  - type: report
    parameters:
      template: sarif-json
      reportDir: /zap/wrk/reports
      reportFile: zap-nightly.sarif.json
  - type: exitStatus
    parameters:
      errorLevel: High
      warnLevel: Medium
Planı zap.yaml olarak kaydedip aynı klasörde çalıştırın:
Bash:
mkdir -p reports && chmod a+w reports
docker run --rm -v "$(pwd):/zap/wrk/:rw" -e ZAP_USER -e ZAP_PASS \
  -t ghcr.io/zaproxy/zaproxy:stable zap.sh -cmd -autorun /zap/wrk/zap.yaml
Plandaki önemli satırlar:
  • excludePaths: Çıkış, hesap silme ve ödeme yolları dışarıda. Örümcek "Çıkış" bağlantısına tıklarsa taramanın geri kalanı oturumsuz geçebilir.
  • browser + autodetect: ZAP arayüzsüz (headless) bir tarayıcıyla giriş sayfasını açar, kullanıcı adı ve parolayı doldurur; oturum belirtecini (cookie ya da Authorization başlığı) ve "giriş yapılmış mı" kontrolünü kendisi bulmaya çalışır.
  • ${ZAP_USER} ve ${ZAP_PASS}: Değişkenler sistem ortamından okunur. Parolayı plana yazmayın; CI'ın gizli değişkenlerinden (secrets) verin.
  • activeScan: maxScanDurationInMins taramaya, maxRuleDurationInMins tek bir kurala üst sınır koyar; delayInMs ve threadPerHost staging sunucusunu yormamak içindir. Saldırı gücü (strength) Low, Medium, High veya Insane; uyarı eşiği (threshold) Off, Low, Medium veya High olabilir.
  • alertFilter: Uyarı filtreleri varsayılan olarak yalnızca yeni oluşan uyarılara uygulanır; bu yüzden bu iş taramalardan önce gelir. Ayrıntısı aşağıda.
  • exitStatus: Planın son işi. High riskli bir uyarı çıkarsa hata (1), Medium çıkarsa uyarı (2) koduyla biter; CI adımının başarısız sayılıp sayılmayacağını bu koda göre belirlersiniz.
Kullanmadığınız teknolojilere (ör. başka bir veritabanı ya da programlama dili) ait kuralları bağlamın technology alanıyla dışarıda bırakmak taramayı kısaltır. Resmî belgelerin önerdiği yol, kimlik doğrulamayı önce ZAP masaüstünde bir bağlamda (context) kurup denemek, ardından planı bu bağlamdan oluşturmaktır; kimlik doğrulama ayarları Automation Framework arayüzünde düzenlenemez.

Kimlik doğrulamalı tarama: en sık bozulan kısım​

Bir uygulamanın asıl saldırı yüzeyi çoğunlukla girişten sonra başlar: profil, sipariş, yönetim ekranları, API'ler. Kimlik doğrulamasız tarama bunların hiçbirini görmez. Daha kötüsü, oturum yarıda düşer ve ZAP bunu fark etmezse isteklerin çoğu giriş sayfasına yönlenir, rapor da yanıltıcı biçimde temiz görünür. Doğrulama (verification) ayarı çalıştığında ZAP oturumun düştüğünü anlar ve yeniden giriş yapar; bu yüzden bu ayarı boş bırakmayın. Yöntem seçimi:
YöntemNe zaman uygun
browser (tarayıcı tabanlı)Klasik giriş formları ve JavaScript ile çalışan giriş sayfaları; kullanıcıya TOTP gizli anahtarı (secret) tanımlanarak iki adımlı doğrulama da geçilebilir
form / jsonGiriş isteği tek bir POST (form ya da JSON gövdesi) olduğunda
httpHTTP Basic, Digest veya NTLM
script / clientÇok adımlı ya da standart dışı akışlar; client yöntemi tarayıcıda kaydedilmiş bir giriş betiğini oynatır
Başlık ortam değişkenleriElinizde hazır bir API belirteci (token) varsa en kısa yol
Belirteçle tarama için ZAP'ın üç ortam değişkeni yeterli:
Bash:
docker run --rm -v "$(pwd):/zap/wrk/:rw" \
  -e ZAP_AUTH_HEADER_VALUE="Bearer $API_TOKEN" \
  -e ZAP_AUTH_HEADER_SITE="api.staging.example.com" \
  -t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \
  -t https://api.staging.example.com/openapi.json -f openapi -r api-report.html
ZAP_AUTH_HEADER_VALUE her isteğe eklenecek değerdir. Başlık adı ZAP_AUTH_HEADER ile değiştirilmezse Authorization kullanılır; ZAP_AUTH_HEADER_SITE ise başlığı yalnızca adında bu değer geçen sitelere gönderir ve belirtecin üçüncü taraf alan adlarına gitmesini önler. Belirtecin ömrü taramadan uzun olmalı: 15 dakikalık bir erişim belirteciyle başlayan iki saatlik bir tarama, yolun büyük kısmını oturumsuz geçirir.

Kimlik doğrulamanın gerçekten çalıştığını kontrol edin: rapordaki URL'ler arasında yalnızca giriş yapmış kullanıcının görebileceği sayfalar var mı, bakın. ZAP masaüstündeki Authentication Tester penceresi aynı ayarları taramadan önce denemenizi sağlar. Her rol (müşteri, bayi, yönetici) için ayrı test kullanıcısı tanımlamak, ileride yetki hatalarını aramanın da ön koşuludur.

API taraması: OpenAPI ve GraphQL​

Tek sayfa uygulamalarda (SPA) ve mobil arka uçlarda asıl hedef API'dir ve örümcek, API uç noktalarının çoğunu bulamaz. zap-api-scan.py, tanımı (OpenAPI, SOAP veya GraphQL; yerel dosya ya da URL) içe aktarır ve bulunan URL'lere aktif tarama uygular. Bu tarama API'lere göre ayarlıdır: XSS gibi tarayıcıya özgü kontrollerle vakit kaybetmez; 5xx sunucu hatası dönen ve API'lerde beklenmeyen içerik türleri döndüren URL'ler için ayrıca uyarı üretir.

Tanımdaki sunucu adresi staging'i göstermiyorsa -O ile ana makine adını değiştirin; Automation Framework'te aynı işi openapi işinin targetUrl alanı görür. GraphQL'de -f graphql verin. Şema verilmezse ZAP onu uç noktadan introspection ile okur; isterseniz --schema ile bir dosya ya da URL gösterebilirsiniz. -S (güvenli mod) aktif taramayı atlayıp yalnızca baseline yapar; canlı bir API'ye ilk bakış için kullanışlıdır.

Tanımın kalitesi taramanın kalitesini belirler. Örnek değerleri olmayan, zorunlu alanları eksik bir OpenAPI dosyası isteklerin çoğunun doğrulama hatasıyla (400) dönmesine ve taranan yüzeyin daralmasına yol açabilir. Taramadan önce tanımı bir şema doğrulayıcıdan geçirin, taramadan sonra da sunucu loglarında isteklerin ne kadarının 400 ile döndüğüne bakın.

Bulguları ayıklamak: risk, güven ve yanlış pozitifler​

ZAP her uyarıya bir risk (High, Medium, Low, Informational) ve bir güven düzeyi (confidence) verir. Öncelik ikisinin birleşimidir: riski High ama güven düzeyi Low olan bir SQL enjeksiyonu uyarısı, elle doğrulanana kadar yalnızca bir şüphedir. Sık görülen uyarılar ve ilk adım:
Kural (ID)Ne anlatırİlk adım
40018-40022, 40024, 40027 SQL InjectionParametre SQL sorgusuna işleniyor olabilir; zamana dayalı (time based) türler yük altındaki sunucuda yanlış alarm verebilirİsteği tekrar gönderip yanıtları karşılaştırın, kodda parametreli sorgu kullanıldığını kontrol edin
40012, 40014, 40026 XSSYansıyan, kalıcı ve DOM tabanlı betik enjeksiyonuYükü tarayıcıda deneyin, çıktı kodlamasını (output encoding) düzeltin
90022 Application Error DisclosureHata sayfası yığın izi (stack trace) ya da sürüm bilgisi sızdırıyorCanlı hata sayfalarını genel bir mesaja çevirin, ayrıntıyı loga yazın
10038, 10055 CSPContent-Security-Policy yok ya da zayıfPolitikayı önce report-only modda yazıp izleyin
10202 Absence of Anti-CSRF TokensFormda CSRF belirteci bulunamadıGET ile çalışan arama formlarında çoğu zaman yanlış pozitif; durum değiştiren formlarda gerçek sorun
10096 Timestamp Disclosure - UnixYanıtta Unix zaman damgasına benzeyen bir sayı varÇoğunlukla zararsız; bağlamı kontrol edip dar bir filtreyle kapatın
Yanlış pozitifi raporda elle silmek işe yaramaz; bir sonraki taramada geri gelir. Kalıcı çözüm, kararı plana yazıp sürüm kontrolünde tutmaktır. Automation Framework'teki alertFilter işi, bir kuralın uyarılarını belirli bir URL, parametre veya kanıt (evidence) için "False Positive" ya da başka bir risk düzeyine çevirir. Hazır betiklerde bu işi kural dosyası görür: IGNORE kuralı tümden kapatır, sekmeyle (tab) ayrılmış 10202 OUTOFSCOPE .*/search.* gibi bir satır kuralı yalnızca eşleşen URL'lerde susturur; düzeltilmekte olan bulgular ise -p ile verilen ilerleme dosyasında (progress file) IN-PROGRESS olarak işaretlenir. Filtreyi olabildiğince dar tutun: 10202'yi tüm site için kapatmak, gerçekten korumasız bir ödeme formunu da gizler. Her filtrenin yanına neden eklendiğini yazın; altı ay sonra kimse hatırlamaz.

Gerçek bulgularda düzeltmeyi de ZAP ile doğrulayın: aynı isteği ZAP masaüstündeki Manual Request Editor penceresiyle yeniden gönderip yanıtı karşılaştırın, düzeltme yayına çıkınca planı tekrar çalıştırın.

CI'a yerleştirmek: hangi tarama ne zaman?​

Her PR'da tam aktif tarama çalıştırmak hem yavaştır hem de staging'i sürekli kirletir. Pratik bir dağılım şöyle:
  • Her PR: baseline (pasif, birkaç dakika). Kurulumu yukarıda andığımız OWASP Top 10 yazısında var.
  • Her gece: staging'e Automation Framework planıyla kimlik doğrulamalı aktif tarama; raporlar artefakt olarak saklanır, High bulgu bildirim üretir.
  • Sürüm öncesi: API taraması ve kritik akışların elle kontrolü.
GitHub Actions'ta gece taraması:
YAML:
name: zap-nightly
on:
  schedule:
    - cron: "30 1 * * *"
  workflow_dispatch:
jobs:
  zap:
    runs-on: ubuntu-latest
    timeout-minutes: 150
    steps:
      - uses: actions/checkout@v7
      - name: ZAP Automation Framework
        env:
          ZAP_USER: ${{ secrets.ZAP_USER }}
          ZAP_PASS: ${{ secrets.ZAP_PASS }}
        run: |
          mkdir -p reports && chmod a+w reports
          docker run --rm -v "$PWD:/zap/wrk/:rw" -e ZAP_USER -e ZAP_PASS \
            ghcr.io/zaproxy/zaproxy:stable zap.sh -cmd -autorun /zap/wrk/zap.yaml || [ $? -eq 2 ]
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: zap-reports
          path: reports/
Konteynerdeki ZAP root olmayan zap kullanıcısıyla çalıştığı için rapor dizinine yazma izni verilir (chmod a+w). GitHub Actions, sıfırdan farklı her çıkış kodunda adımı başarısız sayar. Komutun sonundaki çıkış kodu kontrolü uyarı kodunu (2) kabul eder; böylece başlangıçta iş yalnızca High bulgularda (1) başarısız olur. Ekip alıştıkça bu kontrolü kaldırıp Medium bulgularda da işi durdurabilirsiniz.

ZAP'ın kendi GitHub Actions eylemleri de var: hazır betikleri saran zaproxy/action-baseline, action-full-scan ve action-api-scan, isterseniz bulgular için bir GitHub issue'su açar; Automation Framework planını çalıştıran action-af ise bu seçeneği sunmaz. Docker çalıştırabilen GitLab CI ve Jenkins ajanlarında (agent) aynı komut değişmeden çalışır; pipeline tasarımı için CI/CD yazımıza bakabilirsiniz. İmajı da bilinçli seçin: weekly her hafta değişir; stable ise her tam sürümde ve arada düzenli olarak (belgelere göre en az ayda bir) yeniden üretilir. Bu yeniden üretimler ZAP çekirdeğine dokunmaz ama tarama kuralları dâhil güncel eklentileri getirir; 2.17.0 gibi sürüm etiketleri de onlarla birlikte güncellenir. Sonuç farklarını açıklayabilmek için CI'da imajı özetine (digest) göre sabitleyin (ghcr.io/zaproxy/zaproxy@sha256:...) ve yükseltmeyi ayrı bir değişiklik olarak yapın.

ZAP'ın bulamadıkları​

DAST aracı uygulamayı dışarıdan, kurallara göre dener. İş mantığı hatalarını (indirim kodunun iki kez uygulanması, sipariş adımlarının atlanması), başka bir kullanıcının kaydına erişimi (IDOR), rol bazlı yetki hatalarının çoğunu, yarış koşullarını ve tasarım zayıflıklarını tek başına bulamaz. Access Control Testing eklentisi, hangi rolün hangi URL'ye erişmesi gerektiğini tanımlarsanız karşılaştırma yapabilir; kuralları yine sizin yazmanız gerekir. Kaynak kod analizi (SAST), bağımlılık taraması (SCA) ve dönemsel elle sızma testi bu boşlukları kapatmaya yardım eder. "ZAP sıfır High buldu" cümlesi "uygulama güvenli" demek değildir; "otomatik araçla bulunabilen bariz sorunları kapattık" demektir.

Sık yapılan hatalar​

  • Canlı ortamda izinsiz ya da yedeksiz aktif tarama.
  • Çıkış (logout) yolunu dışlamamak: taramanın büyük kısmı oturumsuz geçebilir.
  • Yönetici hesabıyla taramak: ZAP formları doldururken gerçek kayıtları değiştirebilir ya da silebilir. Silme yetkisi olmayan bir test rolüyle başlayın.
  • Tüm Low ve Informational uyarıları geliştiricilere iş kaydı olarak açmak: ekip raporu okumayı bırakır. Önce High ve Medium.
  • WAF'ın engellediği istekleri temiz sonuç sanmak.
  • İmajı özetiyle (digest) sabitlemeden çalışıp sonuç farklarını açıklayamamak.

Sık sorulan sorular​

ZAP ücretsiz mi?
Evet. ZAP, Apache 2.0 lisanslı açık kaynak bir araçtır ve Checkmarx desteğine geçtikten sonra da açık kaynak kaldı. Ticari DAST ürünleri merkezi yönetim, raporlama ve destek ekler; tarama motoru olarak ZAP tek başına sağlam bir başlangıçtır.

OWASP ZAP ile ZAP aynı araç mı?
Evet. Proje 2023'te OWASP'tan ayrıldı ve adı ZAP olarak kaldı; komutlar, eklentiler ve belgeler aynı çizgide sürüyor. Eski blog yazılarında geçen owasp/ ön ekli Docker imajları yerine resmî belgelerdeki ghcr.io/zaproxy/zaproxy ya da zaproxy/zap-stable imajlarını kullanın.

Aktif tarama ne kadar sürer?
URL ve parametre sayısına, kural setine ve sunucunun hızına bağlıdır; küçük bir sitede dakikalar, büyük bir uygulamada saatler sürebilir. Bu yüzden maxScanDurationInMins ve örümcek süre sınırlarını baştan koyun.

Canlı ortamı hiç tarayamaz mıyım?
Pasif baseline saldırı yükü göndermediği için canlıda genellikle güvenlidir. Aktif taramayı canlıda ancak yazılı izin, yedek, düşük istek hızı ve dar kapsamla, bir bakım penceresinde düşünün.

ZAP mı, Burp Suite mi?
İkisi de araya giren vekil sunucu (intercepting proxy) olarak çalışır. ZAP'ta otomatik zafiyet tarayıcısı (scanner) dâhil her şey ücretsizdir; Docker, YAML planı ve CI ile kolayca otomatikleştirilir. Burp Suite'in ücretsiz Community sürümü elle test araçlarını içerir; web zafiyet tarayıcısı ise ücretli Professional sürümündedir. Birçok ekip CI'da ZAP, elle testte Burp kullanır.

Sonuç ve sonraki adımlar​

  1. Staging'de silme yetkisi olmayan bir test kullanıcısı ve yazılı bir kapsam hazırlayın.
  2. Yukarıdaki planı kendi URL'lerinizle çalıştırın, raporda giriş sonrası sayfaların bulunduğunu doğrulayın.
  3. İlk raporu ayıklayın: yanlış pozitifleri gerekçesiyle alertFilter'a, gerçek bulguları iş takip sisteminize taşıyın.
  4. Planı gece çalışan CI işine bağlayın; başlangıçta işi yalnızca High bulgularda durdurun, ekip alıştıkça Medium bulguları da ekleyin.
Ayrıntılı seçenekler için resmî Automation Framework belgelerine bakın. Kurulumda ya da bulguların yorumlanmasında destek gerekirse AIOR'un siber güvenlik hizmetlerine göz atabilirsiniz.

What this guide covers​

ZAP is an open-source dynamic application security testing (DAST) tool: it tests a web application from the outside while the application is running. For many years it was one of OWASP's flagship projects, which is why most people still search for it as "OWASP ZAP". In August 2023 the project left OWASP to join the Software Security Project under the Linux Foundation, and since September 2024 it has been developed as "ZAP by Checkmarx", still open source under the Apache 2.0 licence.

Our practical web security guide covers the OWASP Top 10:2025 categories and a passive baseline scan in CI. This article picks up from there: active scanning that sends attack payloads, authenticated scanning as a logged-in user, OpenAPI and GraphQL scanning, a repeatable scan plan with the Automation Framework, and triaging what comes back. The commands were checked against the documentation for ZAP 2.17.0 (December 2025) and the official Docker images; options change between releases, so check the -h output of your own version.

Before you scan: permission, scope and environment​

An active scan sends real attacks: it writes SQL injection payloads into form fields, tries script injection on parameters and produces thousands of requests in a short time. Three rules are therefore not negotiable:
  • Written permission. Actively scanning a system you do not own, or have not been explicitly authorised to test, can be a criminal offence. In Türkiye such acts can fall under Articles 243 (accessing an information system) and 244 (hindering or disrupting a system, deleting or altering data) of the Turkish Penal Code, and many other countries have similar computer misuse laws. Check the terms of your hosting, CDN and WAF providers too.
  • Staging, not production. An active scan can create records such as comments, orders and support tickets, trigger e-mails and even delete data. Use a staging environment that resembles production but holds anonymised data, and take a backup before the scan.
  • A team that knows. Tell operations the scan window and the source IP address. Rather than switching the WAF off entirely, allow-list the scanner's IP; otherwise you will read requests the WAF blocked as clean results.
Write the scope down as well: which domains, which paths, which user roles. Leave logout, account deletion, payment and bulk e-mail endpoints out of scope. Preparing for a penetration test by an outside team is covered separately in our pentest engagement article.

The three packaged scans: baseline, full and API​

ZAP's Docker images (ghcr.io/zaproxy/zaproxy:stable, or zaproxy/zap-stable on Docker Hub) ship with three ready-made scan scripts; the small "bare" image built for CI does not include them.
ScriptWhat it doesSends attacks?Where to use it
zap-baseline.pySpiders for 1 minute by default, then runs passive rules onlyNoEvery PR, a light check of production
zap-full-scan.pySpiders with no time limit, optionally runs the AJAX or client spider, then a full active scanYesNightly scan of staging
zap-api-scan.pyImports an OpenAPI, SOAP or GraphQL definition and runs an active scan tuned for APIsYes (baseline only with -S)API check before a release
All three share the same exit codes: 0 clean, 1 at least one FAIL, 2 warnings only, 3 any other failure. Every alert counts as a WARN by default; in the rules file generated with -g you set rules to FAIL or IGNORE. The rules file of the full and API scans also lists the active rules, and active rules set to IGNORE are not run at all, which speeds the scan up.
Bash:
# First run: generate the rules template with every rule set to WARN (-g)
docker run --rm -v "$(pwd):/zap/wrk/:rw" -t ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py -t https://staging.example.com -m 10 -g full-rules.conf -r full-report.html

# Later runs: the edited rules file, the AJAX spider, HTML and JSON reports
docker run --rm -v "$(pwd):/zap/wrk/:rw" -t ghcr.io/zaproxy/zaproxy:stable \
  zap-full-scan.py -t https://staging.example.com -m 10 -j -T 30 \
  -c full-rules.conf -r full-report.html -J full-report.json
-m 10 limits the spider to 10 minutes; the full scan has no limit by default. -j adds the AJAX spider to the traditional spider for pages built with JavaScript, and recent versions accept --client-spider to use the client spider instead. -T 30 waits at most 30 minutes for ZAP to start and for passive scanning to finish. Reports are written to the mounted directory, that is, the folder you ran the command from.

The Automation Framework: the whole scan in one file​

The packaged scripts are a good start. Once authentication, more than one spider, a scan policy and several report formats come into play, the ZAP team's recommended route is the Automation Framework: the whole flow lives in one YAML plan, the plan is versioned in Git, and everyone runs the same scan. A plan has two parts: env, which defines the target, authentication and users, and jobs, which run in order.
YAML:
env:
  contexts:
    - name: staging
      urls:
        - https://staging.example.com
      includePaths:
        - "https://staging.example.com.*"
      excludePaths:
        - ".*/logout.*"
        - ".*/account/delete.*"
        - ".*/checkout/pay.*"
      authentication:
        method: browser
        parameters:
          loginPageUrl: https://staging.example.com/login
        verification:
          method: autodetect
      sessionManagement:
        method: autodetect
      users:
        - name: tester
          credentials:
            username: ${ZAP_USER}
            password: ${ZAP_PASS}
  parameters:
    failOnError: true
    failOnWarning: false
    progressToStdout: true
jobs:
  - type: alertFilter
    alertFilters:
      - ruleId: 10096
        newRisk: "False Positive"
        url: "https://staging.example.com/assets/.*"
        urlRegex: true
  - type: spider
    parameters:
      context: staging
      user: tester
      maxDuration: 10
  - type: spiderAjax
    parameters:
      context: staging
      user: tester
      maxDuration: 10
  - type: passiveScan-wait
    parameters:
      maxDuration: 10
  - type: activeScan
    parameters:
      context: staging
      user: tester
      maxScanDurationInMins: 90
      maxRuleDurationInMins: 10
      delayInMs: 50
      threadPerHost: 4
    policyDefinition:
      defaultStrength: Medium
      defaultThreshold: Medium
  - type: report
    parameters:
      template: traditional-html
      reportDir: /zap/wrk/reports
      reportFile: zap-nightly.html
  - type: report
    parameters:
      template: sarif-json
      reportDir: /zap/wrk/reports
      reportFile: zap-nightly.sarif.json
  - type: exitStatus
    parameters:
      errorLevel: High
      warnLevel: Medium
Save the plan as zap.yaml and run it from the same folder:
Bash:
mkdir -p reports && chmod a+w reports
docker run --rm -v "$(pwd):/zap/wrk/:rw" -e ZAP_USER -e ZAP_PASS \
  -t ghcr.io/zaproxy/zaproxy:stable zap.sh -cmd -autorun /zap/wrk/zap.yaml
The lines that matter:
  • excludePaths: logout, account deletion and payment stay out. If the spider follows a "Log out" link, the rest of the scan can run without a session.
  • browser + autodetect: ZAP opens the login page in a headless browser, fills in the username and password, and tries to work out by itself which token carries the session (a cookie or an Authorization header) and how to tell whether it is still logged in.
  • ${ZAP_USER} and ${ZAP_PASS}: the variables are read from the system environment. Keep passwords out of the plan and pass them from your CI secrets.
  • activeScan: maxScanDurationInMins caps the scan and maxRuleDurationInMins caps any single rule; delayInMs and threadPerHost keep the load on staging reasonable. Attack strength is Low, Medium, High or Insane; the alert threshold is Off, Low, Medium or High.
  • alertFilter: by default, alert filters only apply to alerts raised after they are defined, so this job comes before the scans; more on this below.
  • exitStatus: the last job. The plan exits with an error (1) if any High risk alert is raised and with a warning (2) for Medium, so your CI step can fail on it.
Excluding the rules for technologies you do not use (another database or programming language, for example) through the context's technology section shortens the scan further. The official documentation recommends configuring and testing authentication on a context in the ZAP desktop first, then creating the plan from that context; the Automation Framework UI cannot edit the authentication settings.

Authenticated scanning: the part that breaks most often​

Most of an application's attack surface sits behind the login: profiles, orders, admin screens, APIs. An unauthenticated scan sees none of it. Worse, if the session drops halfway through and ZAP does not notice, most requests end up on the login page and the report looks misleadingly clean. With working verification, ZAP detects the lost session and logs in again, so do not leave the verification settings empty. Choosing a method:
MethodWhen it fits
browser (browser-based)Classic login forms and JavaScript-driven login pages; with a TOTP secret defined for the user it can pass two-factor authentication too
form / jsonThe login is a single POST with a form or JSON body
httpHTTP Basic, Digest or NTLM
script / clientMulti-step or non-standard flows; the client method replays a login script recorded in the browser
Header environment variablesThe shortest route when you already have an API token
For a token, three ZAP environment variables are enough:
Bash:
docker run --rm -v "$(pwd):/zap/wrk/:rw" \
  -e ZAP_AUTH_HEADER_VALUE="Bearer $API_TOKEN" \
  -e ZAP_AUTH_HEADER_SITE="api.staging.example.com" \
  -t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \
  -t https://api.staging.example.com/openapi.json -f openapi -r api-report.html
ZAP_AUTH_HEADER_VALUE is added to every request. Unless ZAP_AUTH_HEADER names another header, it is sent as Authorization, and ZAP_AUTH_HEADER_SITE limits it to sites whose name contains that value, which keeps the token away from third-party domains. The token must outlive the scan: a two-hour scan started with a 15-minute access token runs most of the way without a session.

Confirm that authentication actually worked: the report should list URLs that only a logged-in user can reach. The Authentication Tester dialog in the ZAP desktop lets you try the same settings before a scan. Defining a separate test user for each role (customer, reseller, admin) is also the precondition for hunting authorisation bugs later.

API scanning: OpenAPI and GraphQL​

In single-page applications and mobile back ends the API is the real target, and a spider finds few API endpoints. zap-api-scan.py imports the definition (OpenAPI, SOAP or GraphQL, from a local file or a URL) and runs an active scan against the URLs it finds. The scan is tuned for APIs: it does not waste time on browser-specific checks such as XSS, and it raises extra alerts for URLs that return 5xx server errors or content types you would not expect from an API.

If the server address in the definition does not point at staging, override the hostname with -O; in the Automation Framework the openapi job's targetUrl does the same. For GraphQL pass -f graphql; without a schema ZAP reads it from the endpoint by introspection, or you can point --schema at a file or URL. -S (safe mode) skips the active scan and runs a baseline only, which is handy for a first look at a live API.

The definition sets the quality of the scan. An OpenAPI file without example values and with missing required fields can make most requests fail validation with a 400, shrinking the surface that actually gets tested. Run the definition through a schema validator before the scan, and afterwards check the server logs for how many of the scan's requests came back 400.

Triage: risk, confidence and false positives​

ZAP gives every alert a risk (High, Medium, Low, Informational) and a confidence level. Priority comes from both: a High risk SQL injection with Low confidence is a suspicion until someone confirms it by hand. Common alerts and the first step for each:
Rule (ID)What it meansFirst step
40018-40022, 40024, 40027 SQL InjectionA parameter may reach an SQL query; the time-based variants can raise false alarms on a server under loadResend the request and compare responses; check in the code that the query is parameterised
40012, 40014, 40026 XSSReflected, persistent and DOM-based script injectionTry the payload in a browser; fix the output encoding
90022 Application Error DisclosureAn error page leaks a stack trace or version detailsServe a generic error page in production and log the detail
10038, 10055 CSPContent-Security-Policy missing or weakWrite the policy in report-only mode first and watch the reports
10202 Absence of Anti-CSRF TokensNo CSRF token found in a formOften a false positive on GET search forms; a real issue on state-changing forms
10096 Timestamp Disclosure - UnixA number in the response looks like a Unix timestampUsually harmless; check the context and close it with a narrow filter
Deleting a false positive from the report by hand achieves nothing: it is back in the next scan. The lasting fix is to record the decision in the plan and keep it under version control. The Automation Framework's alertFilter job changes a rule's alerts to "False Positive", or to another risk level, for a specific URL, parameter or evidence. With the packaged scripts the rules file does this job: IGNORE switches a rule off entirely, a tab-separated line such as 10202 OUTOFSCOPE .*/search.* silences it for matching URLs only, and issues that are being fixed are marked IN-PROGRESS through a progress file passed with -p. Keep filters as narrow as you can: switching 10202 off for the whole site also hides a genuinely unprotected payment form. Note next to every filter why it was added; nobody will remember in six months.

Use ZAP to confirm real fixes too: resend the same request with the Manual Request Editor in the ZAP desktop and compare the response, then rerun the plan once the fix is deployed.

Fitting it into CI: which scan, when?​

A full active scan on every PR is slow and keeps polluting staging. A practical split:
  • Every PR: the baseline (passive, a few minutes); the setup is in the OWASP Top 10 guide mentioned above.
  • Every night: an authenticated active scan of staging with the Automation Framework plan; reports are kept as artifacts and High findings trigger a notification.
  • Before a release: the API scan plus a manual check of critical flows.
A nightly scan in GitHub Actions:
YAML:
name: zap-nightly
on:
  schedule:
    - cron: "30 1 * * *"
  workflow_dispatch:
jobs:
  zap:
    runs-on: ubuntu-latest
    timeout-minutes: 150
    steps:
      - uses: actions/checkout@v7
      - name: ZAP Automation Framework
        env:
          ZAP_USER: ${{ secrets.ZAP_USER }}
          ZAP_PASS: ${{ secrets.ZAP_PASS }}
        run: |
          mkdir -p reports && chmod a+w reports
          docker run --rm -v "$PWD:/zap/wrk/:rw" -e ZAP_USER -e ZAP_PASS \
            ghcr.io/zaproxy/zaproxy:stable zap.sh -cmd -autorun /zap/wrk/zap.yaml || [ $? -eq 2 ]
      - uses: actions/upload-artifact@v7
        if: always()
        with:
          name: zap-reports
          path: reports/
Inside the container ZAP runs as the non-root zap user, so the report directory needs write permission (chmod a+w). GitHub Actions fails a step on any non-zero exit code. The exit-code check at the end of the command accepts the warning code (2), so at first the job fails only on High findings (1); once the team is used to it, remove the check and let Medium findings fail the job too.

ZAP also publishes ready-made GitHub Actions: zaproxy/action-baseline, action-full-scan and action-api-scan wrap the packaged scans and can open a GitHub issue with the findings if you want, while action-af runs an Automation Framework plan and has no such option. On GitLab CI and Jenkins agents that can run Docker the same command works unchanged; for pipeline design see our CI/CD article. Choose the image on purpose as well: weekly changes every week, while stable is rebuilt for each full release and regularly in between (at least monthly, according to the docs). Those rebuilds leave the ZAP core alone but bring in updated add-ons, scan rules included, and version tags such as 2.17.0 move with them. To be able to explain changes in results, pin the image by digest in CI (ghcr.io/zaproxy/zaproxy@sha256:...) and upgrade in a separate change.

What ZAP will not find​

A DAST tool probes the application from the outside, following rules. On its own it will not find business logic flaws (a discount code applied twice, a skipped checkout step), access to another user's records (IDOR), most role-based authorisation bugs, race conditions or design weaknesses. The Access Control Testing add-on can compare roles if you define which role should reach which URL, but you still write those rules. Static analysis (SAST), dependency scanning (SCA) and a periodic manual penetration test help close these gaps. "ZAP found zero Highs" does not mean "the application is secure"; it means "we fixed the obvious issues an automated tool can find".

Common mistakes​

  • Active scanning production without permission or a backup.
  • Not excluding logout: much of the scan can run without a session.
  • Scanning with an admin account: while filling in forms, ZAP can modify or delete real records. Start with a test role that cannot delete anything.
  • Opening every Low and Informational alert as a ticket for developers: the team stops reading the report. High and Medium first.
  • Reading requests blocked by the WAF as clean results.
  • Running an image that is not pinned by digest and being unable to explain why the results changed.

Frequently asked questions​

Is ZAP free?
Yes. ZAP is open source under the Apache 2.0 licence and stayed open source after moving to Checkmarx's support. Commercial DAST products add central management, reporting and support; as a scanning engine, ZAP on its own is a solid start.

Are OWASP ZAP and ZAP the same tool?
Yes. The project left OWASP in 2023 and kept the name ZAP; commands, add-ons and documentation carried on along the same line. Instead of the owasp/-prefixed Docker images you may see in older blog posts, use ghcr.io/zaproxy/zaproxy or zaproxy/zap-stable from the official documentation.

How long does an active scan take?
It depends on the number of URLs and parameters, the rule set and the speed of the server: minutes for a small site, hours for a large application. That is why you should set maxScanDurationInMins and spider time limits from the start.

Can I scan production at all?
A passive baseline is generally safe in production because it sends no attack payloads. Consider an active scan of production only with written permission, a backup, a low request rate and a narrow scope, inside a maintenance window.

ZAP or Burp Suite?
Both work as intercepting proxies. In ZAP everything, the automated scanner included, is free and easy to automate with Docker, a YAML plan and CI. Burp Suite Community Edition contains the manual testing tools, while the web vulnerability scanner is part of the paid Professional edition. Many teams use ZAP in CI and Burp for manual testing.

Conclusion and next steps​

  1. Prepare a test user on staging that cannot delete anything, and a written scope.
  2. Run the plan above with your own URLs and confirm that the report contains pages behind the login.
  3. Triage the first report: move false positives into alertFilter with a reason, real findings into your issue tracker.
  4. Wire the plan into a nightly CI job; at first let only High findings fail it, and add Medium once the team is used to it.
For every option, see the official Automation Framework documentation. If you need help with the setup or with interpreting findings, have a look at AIOR's cyber security services.
 
Son düzenleyen:

Forum istatistikleri

Konular
925
Mesajlar
932
Üyeler
26
En son üye
Jessicawatson

Çevrimiçi üyeler

Şu anda çevrimiçi üye yok.

Öne çıkan içerik

AIOR
AIOR TEKNOLOJİ

Tüm ihtiyaçlarınız için Teklif alın

Hosting · Domain · Sunucu · Tasarım · Yazılım · Mühendislik · Sektörel Çözümler

Teklif al

7/24 Destek · Anında yanıt

Geri
Üst