Güvenlik Testi ve DevSecOps← İçindekiler Güvenli Kodlama Eğitimi

Güvenlik Testi ve DevSecOps

B

2021’de Codecov adlı bir CI/CD aracı tedarik zinciri saldırısına uğradı. Saldırgan, Codecov’un betiğini değiştirdi ve binlerce şirketin pipeline’ından gizli anahtarları çaldı. Saldırı 2 ay fark edilmedi. O şirketlerin CI/CD pipeline’larında güvenlik testi vardı ama pipeline’ın kendisi test edilmiyordu.

Güvenli kod yazmak yetmez. Yazılan kodun güvenli olduğunu otomatik olarak kanıtlamak da şarttır. DevSecOps, güvenliği geliştirme sürecinin doğal bir parçası yapar: geliştirici kod yazarken, CI/CD hattı çalışırken, üretime dağıtırken güvenlik testleri otomatik çalışır.

Özlü kural: Güvenlik testi, “bitti” deyince başlayan bir denetim değil, “başladı” deyince çalışan bir sürece gömülmeli. Geliştirici kod gönderdiği an, güvenlik testi çalışmalı ve açık varsa dağıtım durmalı.

Hızlı ipucu: pip install bandit && bandit -r src/ komutunu bugün çalıştır. HIGH seviyeli bulgular, düzeltilmeyi bekliyor.

56.1 SAST (Static Application Security Testing)

SAST, kaynak kodu çalıştırmadan analiz eder. Kodu tarar ve bilmiş güvenlik açığı kalıpları arar. “Bu os.system() çağrısı kullanıcı girdisi içeriyor, bu bir command injection riski” der.

Python SAST Aracı: Bandit

# Bandit kurulumu
pip install bandit

# Tek dosyayi tara
bandit app.py

# Tum projeyi tara
bandit -r src/

# Sonucu JSON olarak kaydet
bandit -r src/ -f json -o bandit-report.json

Bandit çıktısı örneği:

Issue: [B602:user-input-call-subprocess] subprocess call with shell=True
   Severity: HIGH   Confidence: HIGH
   Location: app/utils.py:45
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b602_subprocess_popen_shell_true.html

45  subprocess.call("convert " + filename, shell=True)

Bu bulgu, “satır 45’te shell=True ile kullanıcı girdisi kullanılıyor, command injection riski var” der. Severity (önem) ve Confidence (güven) dereceleri, hangi bulguların öncelikli düzeltilmesi gerektiğini gösterir.

SAST araçları false positive (yanlış alarm) üretir. Bandit’in her bulgusu gerçek bir açık değildir. Önemli olan: HIGH severity + HIGH confidence bulgularını öncelikli düzelt. LOW confidence bulguları incele ama panik yapma. False positive oranını zamanla azaltmak için baseline dosyası oluştur ve bilinen false positive’leri dışla.

Diğer SAST Araçları:

AraçDilTipÖzellik
BanditPythonAçık kaynakHızlı, basit
SemgrepÇokluAçık kaynakÖzel kural yazılabilir
SonarQubeÇokluÜcretsiz/ÜcretliCode quality + security
FortifyÇokluÜcretliKurumsal, detaylı
CodeQLÇokluGitHubGitHub Advanced Security

56.2 DAST (Dynamic Application Security Testing)

DAST, çalışan uygulamayı dışarıdan tarar. Kaynak koda ihtiyacı yoktur. Uygulamaya HTTP istekleri gönderir, SQL injection, XSS, CSRF gibi açıkları canlı test eder. “Kara kutu” testidir: saldırganın bakış açısıyla.

OWASP ZAP

# OWASP ZAP kurulumu (Docker)
docker run -t owasp/zap2docker-stable zap-baseline.py \
    -t https://staging.example.com \
    -r zap-report.html

# Tam tarama (daha yavas, daha detayli)
docker run -t owasp/zap2docker-stable zap-full-scan.py \
    -t https://staging.example.com \
    -r zap-report.html

ZAP raporu şunları bulur:

  • SQL injection açıkları (forma ' OR 1=1 gönderir, yanıtı analiz eder)
  • XSS açıkları (forma <script>alert(1)</script> gönderir)
  • Missing security headers (HSTS, X-Frame-Options, CSP)
  • Broken authentication
  • Session management zafiyetleri

SAST vs DAST:

ÖzellikSASTDAST
Ne tararKaynak kodÇalışan uygulama
Ne zamanCommit/push anındaStaging/pre-prod
HızSaniyeler/dakikalarSaatler
False positiveYüksekDüşük
Açık tipiKod kalıbıÇalışan zafiyet
Dil gerekliEvetHayır (kara kutu)

İkisini birlikte kullan. SAST erken yakalar (geliştirme aşaması), DAST gerçek açığı doğrular (staging aşaması).

56.3 SCA (Software Composition Analysis)

SCA, projenin kullandığı üçüncü parti kütüphanelerdeki bilinen açıkları tarar. Modern uygulamanın %80’i açık kaynak kütüphanelerden oluşur. Senin yazdığın kod güvenli olabilir ama bağımlılıklarında bilinen bir açık varsa, tüm sistemin tehlikededir.

Python Bağımlılık Tarama

# pip-audit: Python bağımlılıklarını CVE veritabanıyla karsilastirir
pip install pip-audit
pip-audit

# Cikti ornegi:
# Found 2 known vulnerabilities in 1 package:
#   flask  == 1.1.0
#     * CVE-2023-30861  HIGH  Flask versions prior to 2.2.5 contain...
#     CVE-2023-36801    MEDIUM  Flask versions prior to 3.0.0 contain...

# safety: Alternatif tarama aracı
pip install safety
safety check --requirements requirements.txt

requirements.txt Analiz:

# Tum bağımlılıkları güncel mi kontrol et
pip list --outdated

# Bilinen aciklara sahip paketler
pip-audit --requirement requirements.txt

# SBOM (Software Bill of Materials) uret
pip install cyclonedx-bom
cyclonedx-py -r -o sbom.json
# SBOM, projenin tum bağımlılık agacini cikarır
# Yeni bir CVE yayinlandiginda "bu kutuphane bizde var mi?" diye SBOM'a bakarsin

Log4Shell (CVE-2021-44228) krizinde SBOM’u olan şirketler 30 dakika içinde etkilenip etkilenmediklerini belirledi. SBOM’u olmayan şirketler günlerce manuel olarak tüm projeleri taradı. SBOM, bağımlılık kriz anında hayati önem taşır. Bu bölümün SCA kısmında SBOM üretimini ve kullanımını detaylıca işledik.

56.4 Fuzzing

Fuzzing, programa rastgele (veya yarı-rastgele) veri gönderip çökme veya beklenmeyen davranış bulma tekniğidir. SAST ve DAST bulamayan açıkları bulur çünkü “bunu denemek kimse aklına gelmez” türünden girdileri otomatik üretir.

# Basit fuzzing ornegi (atheris kutuphanesi)
import atheris
import sys

def test_parser(data: bytes):
    """Parser fonksiyonunu fuzz et"""
    try:
        # Rastgele veriyi parser'a ver
        parsed = my_parser(data)
        assert parsed is not None
    except (ValueError, TypeError):
        pass  # Beklenen hatalar
    # Beklenmeyen crash'ler yakalanir ve raporlanir

# Fuzzing baslat
atheris.Setup(sys.argv, test_parser)
atheris.Fuzz()

Fuzzing türleri:

TürNasıl çalışırÖrnek
Dumb fuzzTamamen rastgele byte’lar/dev/urandom
Smart fuzzFormatı bilir, kurallı üretirJSON grammar ile
Coverage-guidedHangi girdi yeni kod yol açar, onu takip ederAFL, libFuzzer
Grammar-basedDilbilgisi kurallarına göre üretirSQL ifadeleri

AFL (American Fuzzy Lop) ve libFuzzer, en bilinen coverage-guided fuzzing araçlarıdır. Güvenlik açığı araştırmacıları, fuzzing ile sıfırıncı gün (zero-day) açıklar bulur.

Fuzzing production'da mı, test'te mi çalışır?

Asla production’da. Fuzzing, programa kasıtlı olarak geçersiz/bozuk veri gönderir. Bu, production veritabanını bozabilir, hizmet çökertebilir. Fuzzing her zaman test/staging ortamında, izole edilmiş bir sanal makinede çalıştırılır. CI pipeline’ına eklenebilir ama her zaman ayrı bir job olarak, uzun süreli (gece boyu) çalışacak şekilde.

56.5 CI/CD Güvenlik Pipeline’ı

DevSecOps’un kalbi CI/CD pipeline’ıdır. Her commit, her pull request otomatik olarak güvenlik testinden geçer. Manuel denetime gerek yoktur.

GitHub Actions Örneği

# .github/workflows/security.yml
name: Security Pipeline

on: [push, pull_request]

permissions:
  contents: read  # En az yetki prensibi

jobs:
  # 1. SAST: Statik kod analizi
  bandit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4  # SHA ile sabitlemek daha guvenli
      - name: Bandit ile Python kod tara
        run: |
          pip install bandit
          bandit -r src/ -f json -o bandit-report.json || true
      - name: HIGH severity varsa basarisiz ol
        run: |
          if grep -q '"issue_severity": "HIGH"' bandit-report.json; then
            echo "HIGH severity guvenlik acigi bulundu!"
            exit 1
          fi

  # 2. SCA: Bagimlilik taramasi
  dependency-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: pip-audit calistir
        run: |
          pip install pip-audit
          pip-audit --requirement requirements.txt

  # 3. Secret tarama (commit hash ile pinle, @main ASLA)
  secret-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Tam git history
      - name: TruffleHog ile secret tara
        uses: trufflesecurity/[email protected]  # @main DEGIL, spesifik surum

  # 4. Container tarama (Docker image)
  container-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Docker image olustur
        run: docker build -t app:${{ github.sha }} .
      - name: Trivy ile image tara
        uses: aquasecurity/[email protected]  # @master DEGIL, spesifik surum
        with:
          image-ref: app:${{ github.sha }}
          severity: CRITICAL,HIGH
          exit-code: 1  # CRITICAL/HIGH varsa pipeline durur

Bu pipeline’da:

  1. bandit kodu statik olarak tarar
  2. pip-audit bağımlılıkları kontrol eder
  3. trufflehog secret sızıntısı arar
  4. trivy Docker image’ı tarar

Herhangi bir adımda HIGH/CRITICAL bulunursa pipeline durur. Kod üretime ulaşamaz.

Pipeline’ı kademeli kur. İlk hafta sadece “report” modunda çalıştır (uyarı ver ama pipeline’ı durdurma). Ekip tooling alıştığında “enforced” moda geç (pipeline’ı durdur). Bu, “security team broke my build” kültürel direncini azaltır.

56.6 Container ve IaC Güvenliği

Modern altyapı, Docker container ve Terraform/CloudFormation gibi Infrastructure as Code (IaC) üzerine kuruludur. Bunlarda da güvenlik açığı olabilir.

Docker Image Tarama

# KOTU Dockerfile
FROM python:3.11          # full image, cok buyuk, fazla saldiri yuzeyi
RUN apt-get update        # build sirasinda root olarak calisir
COPY . /app               # .env dosyasi da kopyalanir!
CMD ["python", "app.py"]  # root user olarak calisir
# IYI Dockerfile
FROM python:3.11-slim@sha256:<digest>  # Digest ile sabitle (tag degil)
RUN useradd -m appuser    # root olmayan kullanici olustur
COPY --chown=appuser:appuser . /app
# .dockerignore ile .env, .git, __pycache__ dislanmali
USER appuser              # root'tan cik, appuser olarak calis
HEALTHCHECK --interval=30s CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
CMD ["python", "app.py"]

Trivy ile container tarama:

# Docker image'i bilinen aciklar icin tara
trivy image app:latest

# Sadece CRITICAL ve HIGH aciklari goster
trivy image --severity CRITICAL,HIGH app:latest

# Cikti ornegi:
# app:latest (debian 11.8)
# Total: 23 (HIGH: 5, CRITICAL: 1)
#
# CRITICAL: openssl (CVE-2023-5363)
# HIGH:     curl (CVE-2023-48695)
# HIGH:     git (CVE-2023-45323)

IaC Tarama (Terraform)

# tfsec: Terraform kodunu guvenlik acisindan tara
tfsec src/terraform/

# Cikti ornegi:
# [AWS018] AWS S3 bucket is not encrypted
#   src/terraform/storage.tf:12
#   Impact: S3 bucket verileri sifresiz saklaniyor
#   Resolution: server_side_encryption_configuration ekle

# checkov: Alternatif IaC tarayici
checkov -d src/terraform/
Distroless image nedir, neden daha güvenli?

Distroless image, içinde işletim sistemi paket yöneticisi (apt, yum), shell, debug araçları BARINDIRMAYAN minimal Docker image’dir. Sadece uygulama çalışması için gereken paylaşılan kütüphaneler ve uygulamanın kendisi vardır. Avantajı: saldırgan container’a girse bile shell yok, package manager yok, yeni araç indiremez. Saldırı yüzeyi minimumdadır. Google Distroless ve Chainguard Images en bilinen sağlayıcılardır.

SBOM'u pipeline'a nasıl eklerim?

CI/CD pipeline’ında her build’de SBOM üret ve artifact olarak sakla. Syft (container image için) veya cyclonedx (dil bazlı) araçlarını kullan. SBOM’u güncel tut: her yeni build’de yeni SBOM üret, eskisini arşivle. Yeni bir CVE yayınlandığında, en son SBOM’u al, etkilenen paket var mı diye sorgula. SBOM’u olmayan bir proje, bağımlılık krizinde günlerce manuel arama yapar.

Bunu Yap
  • SAST, SCA, secret tarama pipeline'a entegre
  • Docker image'da root yerine non-root kullanıcı kullan
  • Slim veya distroless base image kullan
  • Her build'de SBOM üret
Bunu Yapma
  • .env dosyasını Docker COPY ile kopyala
  • Latest tag kullan (sürüm sabit değil)
  • Pipeline'ı sadece report modda bırak (enforced'a geçmezsen anlamı yok)
  • SAST false positive'lerini görmezden gel
Senaryo: Pipeline Olmasaydı

Bir geliştirici, yeni bir özellik için requests kütüphanesinin eski bir sürümünü ekledi. Bu sürümde bilinen bir açık var (CVE-2024-1234, CVSS 9.8). Ekip hızlı shipping için pipeline’ı atladı, kodu direkt main branch’e merge etti. 1 hafta sonra otomatik bir tarayıcı, şirketin public API’sinde bu açığı buldu. Saldırgan, açığı sömürerek sunucuda kod çalıştırdı. SCA pipeline olsaydı, merge anında “requests 2.20.0’da CRITICAL açık, 2.31.0’a yükselt” derdi ve merge’i engellerdi. Pipeline, birkaç saniyelik gecikme kurtarır; ama milyonlarca liralık ihlal masrafını önler.

DevSecOps Pipeline Kontrol Listesi
  • SAST (Bandit/Semgrep) her PR’da otomatik çalışıyor
  • SCA (pip-audit) bağımlılıkları CVE veritabanıyla kontrol ediyor
  • Secret tarama (TruffleHog) pre-commit hook ve pipeline’da
  • DAST (OWASP ZAP) staging ortamında haftalık çalışıyor
  • Docker image’lar Trivy ile taranıyor
  • IaC (Terraform) tfsec/checkov ile denetleniyor
  • Container non-root kullanıcı ile çalışıyor
  • SBOM her build’de üretiliyor ve saklanıyor
  • Pipeline enforced modda (HIGH/CRITICAL = durdur)
  • False positive’ler için baseline tanımlı

Gerçek olay: 2021’de Codecov adlı bir CI/CD aracı tedarik zinciri saldırısına uğradı. Saldırgan, Codecov’un bash uploader betiğini ele geçirdi ve binlerce şirketin CI/CD pipeline’ına sızdı. Sızan veriler arasında API anahtarları, token’lar ve gizli değişkenler vardı. Saldırı 2 ay fark edilmedi. Ders: CI/CD pipeline’ı güvenlik testi yapan bir araç bile olsa, kendisi de saldırı hedefidir. Tedarik zinciri güvenliği şarttır.

Benzetme: DevSecOps, bir otomobil fabrikasının kalite kontrol bandına benzer. Her parça (kod) monte edilirken (commit), kalite kontrol (SAST) kontrol eder. Boya sonrası (test), denetmen (DAST) aracı test eder. Yola çıkmadan (dağıtım), son muayene (secret scan) yapılır. Hiçbir adım atlanamaz. Atlanan adım, yolda kalmanın garantisidir.

İlgili Bölümler