08 - 개발자를 위한 DevSecOps: CI/CD 파이프라인의 SAST, DAST 및 보안
2024년 2월, 한 보안 연구원은 다음과 같은 공격이 어떻게 이루어지는지 시연했습니다. tj-액션/변경된 파일, 23,000개 이상의 저장소에서 사용되는 GitHub Action, 수천 개 조직의 CI/CD 파이프라인에서 비밀을 유출할 수 있었습니다. 문제는 애플리케이션 코드나 종속성이 아니라 파이프라인에 있었습니다. 그 자체: 소프트웨어를 보호해야 하는 도구가 공격 벡터가 되었습니다.
이 시나리오는 불편한 진실을 반영합니다. 대부분의 팀은 보안에 투자합니다. 애플리케이션 코드를 작성하지만 이를 구축하는 CI/CD 인프라의 보안을 무시합니다. 테스트하고 배포합니다. DevSecOps는 일부 스캐닝 도구를 파이프라인에 통합하는 것뿐만 아니라 하지만 접근 방식이 근본적으로 바뀌었습니다. 안전은 각 단계에서 필수적인 부분이어야 합니다. 출시 전 최종 점검이 아닌 개발 주기에 맞춰 진행됩니다.
DORA 2025 보고서에 따르면 포괄적인 DevSecOps 관행을 채택한 팀은 심각한 취약점의 MTTR(평균 교정 시간)이 4배 단축되었습니다. 준비 또는 프로덕션 단계에서만 보안 테스트를 수행하는 팀과 비교됩니다. 비용 프로덕션 환경의 보안 버그를 수정하는 것보다 평균 100배 더 높습니다. 개발 중에 이를 수정하십시오. "왼쪽 이동" 원칙은 경제적 정당성을 갖습니다. 견고하면서도 기술적이다.
무엇을 배울 것인가
- Shift-Left 보안: 개발 주기 초기부터 보안을 통합합니다.
- Semgrep 및 CodeQL을 사용한 SAST: 소스 코드의 정적 분석
- OWASP ZAP을 사용한 DAST: 실행 중인 애플리케이션에 대한 동적 테스트
- Snyk 및 Trivy를 사용한 SCA: 종속성에 대한 소프트웨어 구성 분석
- Gitleaks 및 TruffleHog를 사용한 비밀 스캐닝: 자격 증명 유출 방지
- Checkov를 사용한 IaC 보안: Terraform 및 Kubernetes 매니페스트 스캔
- 보안 게이트로 GitHub Actions 파이프라인 완성
- DevSecOps 성숙도를 측정하기 위한 지표 및 KPI
Shift-Left 보안: 기본 원칙
"shift-left"라는 용어는 개발 주기를 선으로 시각적으로 표현한 것에서 유래되었습니다. 타임라인은 왼쪽(기획, 개발)에서 오른쪽(테스트, 생산) 순입니다. 이동 왼쪽의 보안은 보안 검사를 가능한 한 가까이 가져가는 것을 의미합니다. 코드가 작성되는 순간: 개발자의 IDE, 사전 커밋 후크, 스테이징 환경뿐만 아니라 풀 요청도 가능합니다.
가장 반응적인 것부터 가장 적극적인 것까지의 Shift-Left 보안 수준은 다음과 같습니다.
- 레벨 0 - 생산: 프로덕션에서만 취약점 스캔이 가능합니다. 늦고 비싸다.
- 레벨 1 - 준비/사전 제작: 테스트 환경의 DAST. 더 좋아졌지만 여전히 느립니다.
- 수준 2 - CI/CD 파이프라인: SAST, SCA, 푸시할 때마다 비밀을 검색합니다. DevSecOps 표준.
- 레벨 3 - 풀 리퀘스트: 각 PR에 대한 자동 보안 검토. 빠르고 상황에 맞는.
- 레벨 4 - 사전 커밋: 커밋하기 전에 로컬을 확인합니다. 즉각적인 피드백.
- 레벨 5 - FDI: 편집기의 보안 플러그인(Snyk IDE, CodeQL 확장). 실시간.
45% 역설
Veracode와 GitLab의 연구에 따르면 AI 도구로 생성된 코드의 45%가 (GitHub Copilot, Cursor, Claude Code)에는 실패할 수 있는 보안 취약점이 있습니다. 기본 보안 테스트. AI가 본질적으로 위험하기 때문이 아니라 복제하기 때문입니다. 훈련 데이터 세트에 존재하는 안전하지 않은 코드 패턴. 이렇게 하면 컨트롤이 CI/CD의 자동화는 바이브 코딩 및 AI 지원 시대에 더욱 중요합니다. 개발. 시리즈 보기 바이브코딩 이 주제에 대해 더 자세히 알아보려면
SAST: 정적 애플리케이션 보안 테스트
SAST는 애플리케이션을 실행하지 않고 소스 코드, 바이트 코드 또는 바이너리를 분석합니다. 취약한 코드 패턴, 잘못된 구성 및 보안 안티 패턴을 찾고 있습니다. 가장 빠른 제어(초 또는 분 단위로 수행 가능)이며 통합이 가능합니다. IDE, 커밋 전 후크 및 CI/CD 파이프라인에서 직접 수행됩니다.
다른 접근 방식에 비해 SAST의 주요 장점은 다음과 같습니다. 소스 코드에서 실행 (실행 중인 애플리케이션 인스턴스가 필요하지 않음), 취약점을 먼저 식별합니다. 거의 실행되지 않는 코드 경로를 포함하여 코드를 100% 분석할 수 있습니다. 가장 큰 단점은 분류 프로세스가 필요한 위양성 비율입니다. 그리고 규칙을 조정합니다.
Semgrep: SAST 오픈 소스 및 빠른 속도
Semgrep은 아마도 2025년 오픈소스 생태계에서 가장 많이 사용되는 SAST 도구일 것입니다.
그 강점은 규칙의 간단한 구문(코드와 거의 동일한 구조)에 있습니다.
분석), 실행 속도 및 TypeScript, JavaScript에 대한 기본 지원,
Python, Go, Java 및 기타 여러 언어. 수천 개의 보안 규칙을 유지 관리합니다.
공식 등록부 semgrep.dev.
# Installazione Semgrep
pip install semgrep
# oppure con Homebrew
brew install semgrep
# Scansione base con ruleset OWASP
semgrep --config p/owasp-top-ten .
# Scansione con regole specifiche per JavaScript/TypeScript
semgrep --config p/javascript .
semgrep --config p/typescript .
# Regole per Angular/Node.js
semgrep --config p/nodejs-express-security .
semgrep --config p/jwt .
# Output in formato SARIF per GitHub Security tab
semgrep --config p/owasp-top-ten --sarif --output semgrep.sarif .
# Output JSON per processing automatico
semgrep --config p/owasp-top-ten --json --output semgrep.json .
# Escludi cartelle non rilevanti
semgrep --config p/owasp-top-ten \
--exclude="node_modules,dist,coverage,*.min.js" .
# Regola custom Semgrep per trovare JWT senza verifica della firma
# .semgrep/jwt-insecure.yaml
# rules:
# - id: jwt-decode-without-verify
# patterns:
# - pattern: jwt.decode($TOKEN, ...)
# - pattern-not: jwt.verify($TOKEN, ...)
# message: "Uso di jwt.decode senza verifica: usa jwt.verify"
# severity: ERROR
# languages: [javascript, typescript]
CodeQL: 심층 의미 분석
GitHub에서 개발한 CodeQL은 Semgrep보다 더 심층적인 분석을 수행합니다. 코드 데이터베이스를 사용하여 SQL과 유사한 언어 쿼리를 작성하여 찾을 수 있습니다. 여러 수준의 함수 호출(오염 분석)을 통해서도 취약점이 발생합니다. LinkedIn은 2026년 2월에 CodeQL과 Semgrep을 모두 사용한다고 발표했습니다. 최적의 코드베이스 적용 범위를 보완합니다. CodeQL은 기본적으로 통합되어 있습니다. GitHub Advanced Security는 공개 저장소에서 무료로 사용할 수 있습니다.
# .github/workflows/codeql.yml
name: CodeQL Security Analysis
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
# Analisi settimanale (domenica alle 2:00 UTC)
- cron: '0 2 * * 0'
permissions:
contents: read
security-events: write
actions: read
jobs:
codeql-analysis:
name: CodeQL Analysis
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: ['javascript-typescript']
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Initialize CodeQL
uses: github/codeql-action/init@dd746615b1a4b1e1c5d3b87432fe040f4c04082 # v3.28.0
with:
languages: {{ matrix.language }}
# Query suite: default, extended, security-extended
queries: security-extended
config: |
paths-ignore:
- node_modules
- dist
- '**/*.test.ts'
- '**/*.spec.ts'
- name: Autobuild
uses: github/codeql-action/autobuild@dd746615b1a4b1e1c5d3b87432fe040f4c04082 # v3.28.0
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@dd746615b1a4b1e1c5d3b87432fe040f4c04082 # v3.28.0
with:
category: "/language:{{ matrix.language }}"
upload: true
SAST: 거짓 긍정 및 분류
SAST의 주요 문제는 오탐(false positive)의 수입니다: 공격적인 규칙 세트 각 커밋에 대해 수백 개의 보고서를 생성하여 프로세스를 지속 불가능하게 만들 수 있습니다. 권장되는 전략은 높은 심각도 프로필(CRITICAL/HIGH만 해당)로 시작하는 것입니다. 특정 코드베이스에 대한 규칙을 조정하고 점진적으로 증가시킵니다. 팀이 도구에 익숙해지면 적용됩니다. 절대 빌드를 차단하지 마세요 확립된 분류 프로세스가 없는 LOW/MEDIUM의 경우.
DAST: 동적 애플리케이션 보안 테스트
SAST가 코드를 실행하지 않고 분석하는 반면, DAST는 코드를 실행하는 동안 애플리케이션을 테스트합니다. 공격자가 하는 것처럼 외부로부터의 실제 공격을 시뮬레이션합니다. DAST SAST가 볼 수 없는 취약점 발견: 서버 구성 문제, 런타임 동작, REST API의 취약점 및 인증 문제 실제 HTTP 요청에서만 나타납니다.
DAST는 대체가 아닌 SAST를 보완합니다. SAST는 취약점의 70~80%를 찾아냅니다. 소스 코드에서 DAST는 런타임에만 나타나는 나머지 20-30%를 찾습니다. 하나를 위해 완전한 보장, 둘 다 필요합니다.
OWASP ZAP: 오픈 소스 생태계의 DAST 표준
OWASP ZAP(Zed Attack Proxy)는 오픈 소스 세계에서 가장 많이 사용되는 DAST 도구입니다. GitHub Actions의 기본 통합. CI/CD에 대한 세 가지 주요 모드를 제공합니다. 기준 스캔 (수동적, 비침습적, 모든 PR에 이상적) 전체 스캔 (활성, 실제 공격 페이로드 사용, 격리된 환경에서만) 전자 API 스캔 (OpenAPI/Swagger에 특화되어 마이크로서비스에 이상적)
# .github/workflows/dast-zap.yml
name: DAST Security Scan (OWASP ZAP)
on:
push:
branches: [main]
workflow_dispatch:
inputs:
target_url:
description: 'URL target per la scansione DAST'
required: true
default: 'https://staging.myapp.com'
permissions:
contents: read
issues: write # ZAP crea issues GitHub per le vulnerabilità trovate
jobs:
zap-baseline-scan:
name: OWASP ZAP Baseline Scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Baseline scan: scansione PASSIVA (non invia payload di attacco)
# Ideale per ogni PR/push - veloce e non invasivo
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.14.0
with:
target: 'https://staging.myapp.com'
rules_file_name: '.zap/rules.tsv'
fail_action: true
cmd_options: '-a -j -l WARN'
# Full scan: scansione ATTIVA (usa payload di attacco reali)
# Solo in ambienti di test isolati, mai in produzione!
# - name: ZAP Full Scan (staging only)
# uses: zaproxy/action-full-scan@v0.11.0
# with:
# target: 'https://staging-isolated.myapp.com'
# API Scan: specializzato per REST API con OpenAPI spec
# - name: ZAP API Scan
# uses: zaproxy/action-api-scan@v0.9.0
# with:
# target: 'https://api.staging.myapp.com/openapi.json'
- name: Upload ZAP Report
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.0
if: always()
with:
name: zap-report
path: report_html.html
# .zap/rules.tsv - personalizzazione regole ZAP
# ID ACTION PARAM
# 10015 WARN # Incomplete or No Cache-control Header Set
# 10038 IGNORE # CSP Header Not Set (gestito separatamente dal server)
# 10096 WARN # Timestamp Disclosure
# 40014 IGNORE # CSRF (se il token CSRF e implementato lato app)
SSR을 사용하는 Angular 프로젝트의 경우 DAST는 연결 가능한 인스턴스에서 실행되어야 합니다. 파이프라인에서. 임시 스테이징 환경에서의 효과적인 전략 및 배포 (예: Firebase 호스팅 미리보기 채널에서) 파이프라인의 일부로 다음을 실행합니다. DAST를 통과한 경우에만 프로덕션 배포를 진행합니다.
# Esempio: Deploy staging effimero + DAST in pipeline Angular
# .github/workflows/angular-devsecops.yml (estratto)
jobs:
deploy-staging:
runs-on: ubuntu-latest
outputs:
staging_url: {{ steps.deploy.outputs.details_url }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- run: npm ci --ignore-scripts
- run: npm run build --configuration=staging
- name: Deploy to Firebase Hosting preview channel
id: deploy
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: {{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: {{ secrets.FIREBASE_SERVICE_ACCOUNT }}
channelId: staging-{{ github.run_id }}
expires: 1d
dast-scan:
needs: deploy-staging
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: ZAP Baseline Scan on ephemeral staging
uses: zaproxy/action-baseline@v0.14.0
with:
target: {{ needs.deploy-staging.outputs.staging_url }}
fail_action: true
rules_file_name: '.zap/rules.tsv'
SCA: 소프트웨어 구성 분석
SCA(Software Composition Analysis)는 애플리케이션의 오픈 소스 종속성을 분석합니다. 알려진 취약점(CVE), 라이센스 문제 및 오래된 패키지를 식별합니다. 시리즈의 이전 기사( 공급망 보안: npm 감사 및 SBOM) npm 감사, Snyk, 종속봇 및 SBOM 생성을 자세히 다룹니다. 이에 우리는 SCA와 IaC 스캐닝을 하나로 제공하는 Trivy에 중점을 두고 있습니다. 통합 DevSecOps 파이프라인에 이상적인 도구입니다.
# Trivy: SCA + container + IaC in un unico tool
# Installazione
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
| sh -s -- -b /usr/local/bin
# Scansione dipendenze npm (SCA)
trivy fs --scanners vuln --pkg-types library .
# Solo vulnerabilità HIGH e CRITICAL (per security gate)
trivy fs --scanners vuln --severity HIGH,CRITICAL \
--pkg-types library --exit-code 1 .
# Output SARIF per GitHub Security tab
trivy fs --scanners vuln --format sarif \
--output trivy-results.sarif .
# Scansione con SBOM output (CycloneDX)
trivy fs --format cyclonedx --output sbom.json .
# File .trivyignore per CVE accettati (con motivazione obbligatoria!)
# .trivyignore
# CVE-2023-44270 # postcss: impatto solo in CLI, non nel build output - review 2026-06-01
# Scansione completa: vuln + segreti + misconfigurazioni
trivy fs --scanners vuln,secret,misconfig .
# GitHub Actions con Trivy Action ufficiale
# - name: Run Trivy vulnerability scanner
# uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca
# with:
# scan-type: 'fs'
# scan-ref: '.'
# scanners: 'vuln,secret'
# severity: 'HIGH,CRITICAL'
# exit-code: '1'
# format: 'sarif'
# output: 'trivy-results.sarif'
비밀 검색: 자격 증명 유출 방지
매주 공개 GitHub에 수천 개의 비밀이 실수로 노출됩니다. API 키, OAuth 토큰, 데이터베이스 비밀번호, 개인 인증서. GitGuardian은 공개 저장소를 모니터링하여 2024년에 1,200만 개 이상이 감지되었다고 보고했습니다. 공개 저장소에 노출된 비밀의 비율은 전년 대비 28% 증가했습니다. 이전. 비밀이 공개 저장소에 있으면(몇 분 동안이라도) 삭제 전) 손상된 것으로 간주하여 즉시 순환해야 합니다.
Gitleaks와 TruffleHog는 비밀 탐지에 가장 많이 사용되는 두 가지 도구입니다. 보완적: Gitleaks는 빠르고 CI/CD에 적합하며 TruffleHog는 적극적으로 확인합니다. 발견된 비밀이 여전히 유효한지 여부(오탐률이 크게 감소)
Gitleaks: 구성 및 통합
# Installazione Gitleaks
brew install gitleaks
# oppure scarica il binario da GitHub Releases
# https://github.com/gitleaks/gitleaks/releases
# Scansione del repository corrente (tutti i commit)
gitleaks detect --source . --verbose
# Scansione solo dei file staged (per pre-commit hook)
gitleaks protect --staged --verbose
# Scansione di un range di commit specifico
gitleaks detect --source . --log-opts HEAD~1..HEAD
# Output in formato JSON
gitleaks detect --source . --report-format json \
--report-path gitleaks-report.json
# Configurazione pre-commit con pre-commit framework
# .pre-commit-config.yaml
# repos:
# - repo: https://github.com/gitleaks/gitleaks
# rev: v8.24.2
# hooks:
# - id: gitleaks
# Configurazione custom .gitleaks.toml
# [extend]
# useDefault = true
#
# [[rules]]
# id = "internal-api-token"
# description = "Token API interno MyCompany"
# regex = '''mycompany_token_[0-9a-zA-Z]{32}'''
# tags = ["token", "internal"]
#
# [allowlist]
# description = "Test fixtures e placeholder sicuri"
# regexTarget = "line"
# regexes = [
# '''EXAMPLE_TOKEN_PLACEHOLDER''',
# '''test_secret_[a-z0-9]{8}'''
# ]
# paths = [
# '''.*_test\.ts''',
# '''.*\.spec\.ts''',
# '''.*\.fixture\.ts'''
# ]
TruffleHog: 활성 비밀 확인
# Installazione TruffleHog
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \
| sh -s -- -b /usr/local/bin
# Scansione con verifica attiva (riduce falsi positivi)
trufflehog git file://. --only-verified
# Scansione di un repository remoto
trufflehog github --repo https://github.com/myorg/myrepo --only-verified
# Output JSON per processing
trufflehog git file://. --json --no-verification
# GitHub Actions: secrets scanning su ogni push/PR
# .github/workflows/secrets-scan.yml
# - name: TruffleHog secrets scan
# uses: trufflesecurity/trufflehog@main
# with:
# path: ./
# base: $GITHUB_BASE_REF
# head: HEAD
# extra_args: --only-verified
# Differenza chiave Gitleaks vs TruffleHog:
# - Gitleaks: veloce, pattern matching, ottimo per pre-commit e CI
# - TruffleHog: verifica attiva (testa il secret contro l'API reale)
# Risultato: meno falsi positivi, ma più lento e invasivo
# Raccomandazione: entrambi in pipeline (Gitleaks fast, TruffleHog verified)
git rm으로 비밀이 제거되지 않습니다
실수로 비밀을 커밋한 경우 다음을 사용하여 파일을 제거하세요. git rm 또는
파일을 추가하다 .gitignore 충분하지 않다: 비밀은 아직이다
Git 기록에 표시됩니다. 실제로 제거하려면 다음을 사용하십시오. git filter-repo
(GitHub에서 공식적으로 권장하는 도구) 모든 브랜치를 강제로 푸시합니다.
비밀이 훼손된 것으로 간주하고 즉시 교체하세요. GitHub는 또한 다음을 제공합니다.
모니터링하는 저장소 설정의 기본 "비밀 검색" 도구
200개 이상의 알려진 토큰 유형에 대한 기록을 지속적으로 커밋합니다.
IaC 보안: Terraform 및 Kubernetes용 Checkov
IaC(Infrastructure as Code)는 인프라 관리를 민주화했지만 또한 Terraform, Kubernetes 파일의 잘못된 구성이라는 새로운 위험 벡터를 도입했습니다. 전체 인프라를 노출할 수 있는 매니페스트, Docker Compose 및 AWS CloudFormation입니다. Checkov(Bridgecrew/Palo Alto Networks)는 1000개 이상의 파일을 정적으로 검사합니다. CIS 벤치마크, NIST 및 기타 표준에 매핑된 통합 보안 정책입니다.
참고: Aqua Security의 원래 IaC 스캐닝 도구인 tfsec가 통합되었습니다. 트리비에서. 새로운 프로젝트의 경우 IaC용 Trivy 또는 더 넓은 적용 범위를 위한 Checkov를 권장합니다.
# Installazione Checkov
pip install checkov
# oppure con Homebrew
brew install checkov
# Scansione directory Terraform
checkov -d ./terraform
# Scansione Kubernetes manifests
checkov -d ./k8s --framework kubernetes
# Scansione Dockerfile
checkov -f Dockerfile --framework dockerfile
# Output in formato SARIF per GitHub Security
checkov -d ./terraform --output sarif --output-file checkov.sarif
# Skippa check specifici (con commento di motivazione!)
checkov -d ./terraform --skip-check CKV_AWS_18,CKV_AWS_21
# Violazioni Terraform AWS comuni che Checkov rileva:
# CKV_AWS_18: S3 bucket - access logging disabilitato
# CKV_AWS_57: S3 bucket - ACL pubblica (mai in produzione!)
# CKV_AWS_87: Lambda - non in VPC
# CKV_AWS_135: EC2 - IMDSv1 abilitato (usa IMDSv2)
# Esempio Kubernetes manifest INSICURO (violazioni Checkov):
# apiVersion: v1
# kind: Pod
# spec:
# containers:
# - name: app
# image: myapp:latest # CKV_K8S_14: usa tag specifico, non :latest
# securityContext:
# runAsRoot: true # CKV_K8S_6: non eseguire come root
# privileged: true # CKV_K8S_16: non usare privileged mode
# resources: {} # CKV_K8S_11: definisci resource limits
# Esempio Kubernetes manifest SICURO (supera Checkov):
# spec:
# containers:
# - name: app
# image: myapp:1.2.3
# securityContext:
# runAsNonRoot: true
# runAsUser: 1000
# allowPrivilegeEscalation: false
# readOnlyRootFilesystem: true
# resources:
# limits:
# memory: "256Mi"
# cpu: "500m"
# requests:
# memory: "128Mi"
# cpu: "250m"
GitHub Actions 파이프라인 완료: 최고의 보안 게이트
이러한 모든 도구를 하나의 일관된 파이프라인으로 통합하려면 계획이 필요합니다. 주의하세요. 모든 작업이 빌드를 차단할 필요는 없으며 일부 스캔이 더 적합합니다. PR의 경우 다른 것들은 메인 푸시를 위한 것이며 병렬화는 비 개발 흐름이 지나치게 느려집니다. 다음 파이프라인은 하나를 보여줍니다. 6개의 병렬 및 순차 작업으로 완전한 구성.
# .github/workflows/devsecops-complete.yml
name: DevSecOps Security Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 3 * * 1' # Ogni lunedi alle 3:00 UTC (scan completo)
# Permissions minime a livello workflow (principio del minimo privilegio)
permissions:
contents: read
jobs:
# ===== JOB 1: SECRETS SCANNING (primo - fail fast) =====
secrets-scan:
name: Secrets Scanning
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # Storia completa per Gitleaks
- name: Gitleaks secrets detection
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: {{ secrets.GITHUB_TOKEN }}
# ===== JOB 2: SCA - Dependency Vulnerabilities =====
sca-scan:
name: SCA Dependency Audit
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: '22'
cache: 'npm'
- run: npm ci --ignore-scripts
- name: npm audit (solo production deps)
run: npm audit --audit-level=high --omit=dev
- name: Trivy SCA scan
uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca
with:
scan-type: 'fs'
scan-ref: '.'
scanners: 'vuln'
severity: 'HIGH,CRITICAL'
exit-code: '1'
format: 'sarif'
output: 'trivy-vuln.sarif'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@dd746615b1a4b1e1c5d3b87432fe040f4c04082
if: always()
with:
sarif_file: 'trivy-vuln.sarif'
# ===== JOB 3: SAST - Static Code Analysis =====
sast-scan:
name: SAST Static Analysis
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
actions: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Initialize CodeQL
uses: github/codeql-action/init@dd746615b1a4b1e1c5d3b87432fe040f4c04082
with:
languages: 'javascript-typescript'
queries: security-extended
- name: Autobuild
uses: github/codeql-action/autobuild@dd746615b1a4b1e1c5d3b87432fe040f4c04082
- name: CodeQL Analysis
uses: github/codeql-action/analyze@dd746615b1a4b1e1c5d3b87432fe040f4c04082
with:
category: "/language:javascript-typescript"
- name: Semgrep SAST
uses: semgrep/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/javascript
p/typescript
p/jwt
env:
SEMGREP_APP_TOKEN: {{ secrets.SEMGREP_APP_TOKEN }}
# ===== JOB 4: IaC Security =====
iac-scan:
name: IaC Security Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Trivy config scan
uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca
with:
scan-type: 'config'
scan-ref: '.'
severity: 'HIGH,CRITICAL'
exit-code: '1'
- name: Checkov IaC scan
uses: bridgecrewio/checkov-action@v12
with:
directory: .
framework: all
soft_fail_on: MEDIUM
hard_fail_on: HIGH,CRITICAL
# ===== JOB 5: DAST (solo su push a main) =====
dast-scan:
name: DAST ZAP Baseline
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [secrets-scan, sca-scan, sast-scan]
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.14.0
with:
target: {{ secrets.STAGING_URL }}
fail_action: true
- name: Upload ZAP Report
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1
if: always()
with:
name: zap-report-{{ github.sha }}
path: report_html.html
retention-days: 30
# ===== JOB 6: SBOM (su push a main dopo tutti i check) =====
sbom-generate:
name: Generate SBOM
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs: [sca-scan, sast-scan, iac-scan]
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af
with:
node-version: '22'
- run: npm ci --ignore-scripts
- name: Generate SBOM (CycloneDX)
run: |
npm install -g @cyclonedx/cyclonedx-npm
cyclonedx-npm --omit dev \
--output-format json \
--output-file sbom-{{ github.sha }}.json
- name: Attest SBOM
uses: actions/attest-build-provenance@v1
with:
subject-path: sbom-{{ github.sha }}.json
- name: Upload SBOM
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1
with:
name: sbom-{{ github.sha }}
path: sbom-{{ github.sha }}.json
retention-days: 365
보안 게이트: 어떤 블록이 구축되고 어떤 블록이 구축되지 않는가
효과적인 보안 게이트는 모든 경고를 차단하는 것이 아니라 문제를 구별합니다. 즉각적인 주의가 필요한 문제와 시간이 지남에 따라 관리할 수 있는 문제입니다. 기본 규칙은 다음과 같습니다. 명백히 위험하고 실행 가능한 것만 차단합니다.. 너무 많은 오탐지 또는 낮은 취약점으로 인해 빌드를 차단하면 팀이 비활성화됩니다. 통제가 완전히 이루어지지 않아 전체 투자가 망가집니다.
보안 게이트 매트릭스 권장
- 항상 차단: 코드의 비밀, 수정된 심각한 취약점 사용 가능, SAST 주입/RCE 결과, IaC 구성 오류 심각 (S3 퍼블릭 버킷, 수신 SSH의 보안 그룹 0.0.0.0/0)
- 메인 블록(PR 아님): 수정 가능한 취약점이 높음 FAIL로 설정된 DAST 결과, 호환되지 않는 라이선스(GPL의 종속성) 상업용 제품)
- 경고(알리지만 차단하지는 않음): 수정되지 않은 취약점 높음 사용 가능, SAST의 MEDIUM, IaC HIGH(해결 방법은 예외, DAST 결과가 WARN으로 설정됨
- 무시(문서 포함): LOW/INFO 취약성, 오탐지 예외 파일(.trivyignore, .gitleaks.toml 허용 목록)에 문서화되어 있습니다. 특정 애플리케이션 컨텍스트에 실제 영향을 미치지 않는 CVE
# Gestione delle eccezioni documentate nei file di configurazione
# .trivyignore - CVE accettati con motivazione obbligatoria
# Formato: CVE-ID # [data] Motivazione e piano di revisione
CVE-2023-44270 # [2026-02-01] postcss: impatto solo in CLI usage, non nel build output. Review 2026-06
# .gitleaks.toml - allowlist per pattern non pericolosi
# [allowlist]
# description = "Test fixtures, placeholder e valori di esempio"
# regexes = [
# '''EXAMPLE_API_KEY_[A-Z0-9]{16}''',
# '''test_secret_placeholder''',
# '''YOUR_TOKEN_HERE'''
# ]
# paths = [
# '''.*\.spec\.ts''',
# '''.*\.fixture\.ts''',
# '''README\.md'''
# ]
# Semgrep - eccezione inline nel codice sorgente
# Aggiungi commento sulla stessa riga per sopprimere un finding
# const regex = new RegExp(userPattern); // nosemgrep: javascript.lang.security.audit.unsafe-regex
# Checkov - soppressione inline nel file Terraform
# resource "aws_s3_bucket" "cdn_assets" {
# bucket = "my-public-cdn-assets"
# #checkov:skip=CKV_AWS_57: Bucket CDN per assets statici pubblici - progettato per essere pubblico
# }
각도 체크리스트: DevSecOps 파이프라인
Angular 프로젝트에는 다음과 관련된 특정 DevSecOps 고려 사항이 있습니다. 툴체인(Angular CLI, esbuild, ng-packagr), 바인딩이 있는 HTML 템플릿 사용 동적이며 Node.js 서버 Express를 사용하는 SSR입니다.
# Angular DevSecOps Checklist
# 1. SAST: regole Semgrep specifiche per Angular
# Patterns pericolosi da rilevare:
# - DomSanitizer.bypassSecurityTrustHtml(userInput) senza sanitizzazione
# - [innerHTML]="untrustedData" (binding HTML non sicuro)
# - eval() o new Function() in servizi Angular
# - HttpClient senza interceptor di autenticazione
# 2. SECRETS: environment files NON devono contenere valori reali
# SBAGLIATO - environment.ts committato con secret:
# export const environment = {
# apiKey: 'sk-prod-real-key-12345', # Bloccato da Gitleaks!
# googleMapsKey: 'AIza...' # Bloccato da Gitleaks!
# };
# CORRETTO - placeholder nei file committati, valori iniettati in CI:
# export const environment = {
# apiKey: '', // iniettato a build time dalla pipeline CI/CD
# };
# In pipeline: sed -i "s/apiKey: ''/apiKey: '{{ secrets.API_KEY }}'/" src/environments/environment.prod.ts
# 3. CSP HEADER nel server SSR Angular (Express)
# server.ts
# import { randomBytes } from 'crypto';
# const generateNonce = () => randomBytes(16).toString('base64');
#
# app.use((req, res, next) => {
# const nonce = generateNonce();
# res.locals['nonce'] = nonce;
# res.setHeader('Content-Security-Policy', [
# "default-src 'self'",
# `script-src 'self' 'nonce-${nonce}'`,
# "style-src 'self' 'unsafe-inline'",
# "img-src 'self' data: https:",
# "connect-src 'self' https://api.myapp.com",
# "frame-ancestors 'none'"
# ].join('; '));
# next();
# });
# 4. SAST Semgrep per Angular (regola custom bypassSecurityTrust)
# .semgrep/angular-security.yaml
# rules:
# - id: angular-bypass-security-trust
# patterns:
# - pattern: this.$SANITIZER.bypassSecurityTrust$TYPE(...)
# message: "Uso di bypassSecurityTrust$TYPE: verifica la sanitizzazione del valore"
# severity: WARNING
# languages: [typescript]
# 5. Verifica e aggiornamento Angular LTS
ng version
npm outdated @angular/core @angular/cli @angular/material
npm audit --omit=dev --audit-level=high
DevSecOps 성숙도에 대한 지표 및 KPI
개선을 위해서는 측정이 필수적입니다. DevSecOps 측정항목의 균형이 유지되어야 합니다. 안전 효율성을 갖춘 개발 속도. 목표는 결코 0이 아니다 취약성(도달 불가능)이지만 위험을 허용 가능한 수준으로 줄입니다. 가능한 한 가장 짧은 시간에.
필수 DevSecOps KPI
- MTTD(평균 감지 시간): 하나의 도입 사이의 평균 시간 취약점과 그 탐지. CI/CD 대상: 24시간 이내. 전체 Shift-왼쪽(사전 커밋): 초 단위로 감지합니다.
- MTTR(평균 수정 시간): 탐지부터 교정까지 생산 중. OWASP 목표: CRITICAL의 경우 7일 미만, HIGH의 경우 30일 미만. 성숙한 DevSecOps 프로세스: 기존 팀보다 MTTR이 4배 낮습니다.
- SLDR(왼쪽 이동 감지 비율): 취약성 비율 개발과 프로덕션에서 감지되었습니다. 대상: 배포 전 80% 이상이 감지되었습니다.
- 보안 부채: 심각도별 공개 취약점의 총 개수입니다. 시간이 지남에 따라 추세를 모니터링하십시오. 추세는 감소하거나 안정적으로 유지되어야 합니다.
- 거짓양성률: 거짓 긍정 SAST/DAST 경고 비율. 목표: 팀의 피로를 방지하고 프로세스의 신뢰성을 유지하기 위해 20% 미만입니다.
- 파이프라인 기간: 총 DevSecOps 파이프라인 시간. 대상: 생산성에 영향을 미치지 않도록 10분 이내에 SAST + SCA + 비밀을 생성합니다.
- 보안 범위: SAST가 다루는 코드베이스의 비율, DAST가 적용되는 API 비율입니다. 목표: SAST의 경우 90% 이상.
# Script per generare un report KPI di sicurezza dal progetto
# Conta vulnerabilità aperte con npm audit
npm audit --json | jq '.metadata.vulnerabilities'
# Output: { "info": 2, "low": 5, "moderate": 3, "high": 1, "critical": 0, "total": 11 }
# Conta findings SAST da Semgrep (JSON output)
semgrep --config p/owasp-top-ten --json . 2>/dev/null \
| jq '.results | group_by(.extra.severity) | map({severity: .[0].extra.severity, count: length})'
# Verifica durata pipeline (GitHub Actions API)
curl -s -H "Authorization: token $GITHUB_TOKEN" \
"https://api.github.com/repos/$OWNER/$REPO/actions/runs?per_page=10" \
| jq '[.workflow_runs[] | select(.name == "DevSecOps Security Pipeline") | {
run_id: .id,
status: .status,
conclusion: .conclusion,
duration_seconds: ((.updated_at | fromdateiso8601) - (.run_started_at | fromdateiso8601))
}]'
# Badge GitHub Actions per status sicurezza nel README
# 
DevSecOps 문화: 인적 요소
기술만으로는 충분하지 않습니다. DevSecOps에는 문화적 변화가 필요합니다. 보안을 전문팀의 책임에서 책임으로 바꾸는 것 모든 개발자가 공유합니다. 이를 위해서는 교육과 명확한 프로세스가 필요하며, 무엇보다도 안전을 하나의 장애물이 아닌 인식된 장애물로 만드는 마찰 제거 품질 도구.
성숙한 DevSecOps 문화의 기본 원칙은 다음과 같습니다.
- "코드로서의 보안": 보안 정책은 코드로, 버전별로 관리됩니다. git에서는 다른 코드베이스 변경과 마찬가지로 검토됩니다. 정책의 예외 근거 및 개정 날짜와 함께 코드 자체에 문서화되어 있습니다.
- 즉각적이고 상황에 맞는 피드백: 개발자는 다음으로부터 피드백을 받습니다. 몇 주가 지나도 이해할 수 없는 PDF 보고서로 IDE 또는 PR의 보안을 보장합니다. 문맥이 중요합니다. "이 함수에는 42행에 SQL 주입 문제가 있습니다." "백엔드 모듈에서 감지된 취약점 유형 A07"보다 훨씬 더 유용합니다.
- 비난하지 말고, 그래 배우세요: CI/CD에서 발견된 취약점은 처벌이 아닌 학습 기회. 소개해준 개발자 앞으로 이러한 문제가 발생하는 이유와 예방 방법을 이해해야 합니다.
- 보안 챔피언 프로그램: 모든 팀에는 보안 챔피언이 있습니다. 개발팀과 보안팀 사이의 가교 역할을 하며 초기 경고 분류를 수행하고 상황에 맞는 방식으로 모범 사례를 제공합니다.
- 예방적 위협 모델링: 기능을 구현하기 전에 팀은 잠재적인 공격 벡터에 대해 논의합니다. STRIDE(스푸핑, 변조, 거부, 정보 공개, DoS, 권한 상승) 및 프레임워크 이 과정은 간단하고 실용적입니다.
지금 DevSecOps를 시작하기 위한 빠른 승리
처음부터 시작하는 경우 모든 것을 한 번에 구현하려고 하지 마세요. 여기 20%의 노력으로 80%의 위험을 감당하는 세 단계:
-
사전 커밋에 Gitleaks 추가: 사전 커밋 프레임워크를 설치합니다.
Gitleaks 구성 추가
.pre-commit-config.yaml, 달리다pre-commit install. 비밀이 도달하기 전에 누출되는 것을 방지 원격 저장소. 예상 시간: 30분. -
CI에서 GitHub Didabot 및 npm 감사 활성화: 다음에서 dependencyabot을 활성화하세요.
저장소 설정 및 추가
npm audit --audit-level=high --omit=dev기존 CI 파이프라인에 추가합니다. 취약한 종속성에 대한 자동 경고를 받습니다. 예상 시간: 1시간. - GitHub에서 CodeQL 활성화: 공개 저장소에는 무료, 포함됨 기업 개인 저장소를 위한 GitHub Advanced Security에 있습니다. 매일 자동 SAST 추가 구성이 필요 없는 푸시 및 풀 요청. 예상 시간: 15분.
결론 및 다음 단계
DevSecOps는 구매할 제품이나 설치할 도구가 아닙니다. 프로세스입니다. 보안, 개발, 운영을 하나의 주기로 통합하는 지속적인 개선 덕이 있는. 이 문서에 제시된 파이프라인은 모든 주요 계층을 포함합니다. 자격 증명 누출을 방지하기 위한 비밀 검색, 종속성을 위한 SCA, SAST 소스 코드는 DAST, 런타임은 DAST, 인프라는 IaC 보안, 추적성 및 규정 준수를 위한 SBOM 생성.
기본 원칙은 항상 동일합니다. 가능한 한 빨리 문제를 찾아내는 것입니다. 교정 비용은 최소화됩니다. AI 생성 코드 중 45%가 실패 기본 보안 테스트, DevSecOps 자동화는 시대에 더욱 중요해졌습니다. 인공지능을 활용한 개발. 우리는 그것에 의존할 수 없습니다 고속 개발 환경에서는 수동 검토에만 의존합니다.
이 기사로 시리즈를 마무리합니다 개발자를 위한 웹 보안: 우리는 OWASP 상위 10개 취약점부터 전체 보안 스택을 살펴보았습니다. 백엔드 보안부터 암호화, DevSecOps까지 프런트엔드 방어까지 자동화되고 측정 가능한 프로세스에서 모든 모범 사례를 통합하는 접착제입니다. 보안은 최종 제품이 아니라 지속적인 여정입니다. 각 릴리스는 소프트웨어의 보안 상태를 개선할 수 있는 기회입니다.
전체 시리즈: 개발자를 위한 웹 보안
- 01 - 2025년 OWASP 상위 10대: 개발자 가이드
- 02 - XSS, CSRF 및 CSP: 프런트엔드 보안
- 03 - SQL 주입 및 입력 검증: 백엔드 보안
- 04 - 보안 인증: 세션 및 쿠키
- 05 - API 보안: OAuth 2.1, JWT 및 속도 제한
- 06 - 공급망 보안: npm 감사 및 SBOM
- 07 - 암호화 오류: 해싱, 암호화 및 토큰
- 08 - 개발자를 위한 DevSecOps: CI/CD의 SAST, DAST (이 기사)
시리즈에 대해서도 자세히 알아보세요. DevOps 프런트엔드(ID 250-255) Angular 배포 워크플로우와 보안을 통합하는 시리즈 바이브코딩 위험을 이해하기 위해 AI 생성 코드와 관련된 보안 문제와 DevSecOps를 통해 이를 완화하는 방법.







