Secure Development Lifecycle (SDL)
Integrate security into every phase of software development — threat modeling with STRIDE, SAST/DAST automation, dependency scanning, secrets management, and DevSecOps pipeline security.
Learning Objectives
- → Apply STRIDE threat modeling to identify security requirements
- → Configure SAST tools (Semgrep, Bandit) in CI/CD pipelines
- → Use DAST tools (OWASP ZAP) for automated web security testing
- → Scan dependencies for known CVEs with SBOM and Dependabot
- → Implement secrets management to eliminate hardcoded credentials
The Cost of Security
Security cost by phase (relative):
Design phase: $1 (fix a design flaw in architecture)
Development: $6 (refactor the code)
Testing: $15 (fix after QA finds it)
Production: $100+ (breach, reputation damage, legal)
"Shift Left": move security earlier in development
Goal: find and fix security issues at design/code time, not after breach
SDL Phases:
1. Requirements — security requirements from compliance, risk assessment
2. Design — threat modeling, attack surface analysis
3. Implementation — secure coding, SAST, code review
4. Verification — DAST, penetration test, fuzzing
5. Release — final security review, SDL checklist
6. Response — IR plan, patch management, bug bounty
STRIDE Threat Modeling
STRIDE: Microsoft's threat classification framework
Applied per component: "what threats exist to THIS element?"
S — Spoofing Identity
Threat: attacker impersonates a user or service
Defense: authentication (MFA, certificates, OAuth)
T — Tampering with Data
Threat: attacker modifies data in transit or at rest
Defense: integrity checks (HMAC, digital signatures, TLS)
R — Repudiation
Threat: user denies performing an action
Defense: audit logging, non-repudiation (digital signatures)
I — Information Disclosure
Threat: unauthorized access to sensitive data
Defense: encryption, access control, data minimization
D — Denial of Service
Threat: legitimate users can't access service
Defense: rate limiting, input validation, WAF, CDN
E — Elevation of Privilege
Threat: normal user gains admin/system access
Defense: least privilege, authorization checks, input validation
Threat modeling process:
1. Decompose: identify components, data flows, trust boundaries
2. Enumerate: for each component, apply STRIDE
3. Rate: DREAD or CVSS for each threat
4. Mitigate: identify controls, verify they address the threat
Tools: Microsoft Threat Modeling Tool (free), OWASP Threat Dragon
SAST (Static Application Security Testing)
# SAST: analyze source code without executing it
# Finds: SQL injection, XSS, hardcoded secrets, insecure functions
# Semgrep: fast, pattern-based, multi-language SAST
pip3 install semgrep
# Run against a project:
semgrep --config auto ./src/ # community rules
semgrep --config p/python-security ./src/ # Python-specific rules
semgrep --config p/owasp-top-10 ./src/
# Custom rule example:
cat > no_eval.yaml << 'EOF'
rules:
- id: no-eval
patterns:
- pattern: eval(...)
message: "Dangerous use of eval() — code injection risk"
severity: ERROR
languages: [javascript, python]
EOF
semgrep --config no_eval.yaml ./src/
# Bandit: Python-specific SAST
pip3 install bandit
bandit -r ./src/ -ll # low level issues and above
bandit -r ./src/ -f json -o results.json
# ESLint with security plugins:
npm install eslint-plugin-security
# Finds: NoSQL injection, path traversal, eval(), Buffer vulnerabilities
# CodeQL (GitHub): semantic code analysis
# GitHub Actions:
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with: languages: 'python, javascript'
- name: Analyze
uses: github/codeql-action/analyze@v2
DAST (Dynamic Application Security Testing)
# DAST: test running application — finds what SAST misses
# Interaction-based: actually sends HTTP requests, observes responses
# OWASP ZAP (Zed Attack Proxy):
# GUI: run ZAP, configure browser proxy, browse app, Active Scan
# CLI:
docker run -t owasp/zap2docker-stable zap-baseline.py -t https://TARGET_URL
# ZAP in CI/CD (GitHub Actions):
- name: ZAP Scan
uses: zaproxy/[email protected]
with:
target: 'https://staging.myapp.com'
rules_file_name: '.zap/rules.tsv'
# Nuclei: fast vulnerability scanner with community templates
go install github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
nuclei -u https://target.com -t cves/ # CVE checks
nuclei -u https://target.com -t exposures/ # exposed endpoints
nuclei -u https://target.com -severity critical,high
# Burp Suite Pro: automated scanner + manual
# Configure in CI: Burp Scan via API
Dependency Scanning & SBOM
# Dependencies often have more vulnerabilities than your own code!
# npm, pip, maven packages can have critical CVEs
# SBOM (Software Bill of Materials): list of all dependencies
# Required by US Executive Order 14028 (federal software)
# Python: pip-audit
pip install pip-audit
pip-audit
# Output: found 5 vulnerabilities in 2 packages (CVE-2023-xxxx)
# JavaScript: npm audit
npm audit
npm audit fix # auto-fix safe updates
npm audit fix --force # force update (may break APIs)
# Snyk: comprehensive SAST + dependency scanning
npm install -g snyk
snyk auth
snyk test # scan dependencies for CVEs
snyk code test # SAST scan
# GitHub Dependabot: automatic PRs for vulnerable dependencies
# .github/dependabot.yml:
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
security-updates-only: true
# SBOM generation:
# Syft: generates SBOM in SPDX, CycloneDX formats
syft dir:. -o cyclonedx-json=sbom.json
# Grype: vulnerability scanner using SBOM
grype sbom:sbom.json
Secrets Management
# Never hardcode secrets in code!
# .env files should never be committed to git
# Git pre-commit hook to prevent secrets:
pip3 install pre-commit
pip3 install detect-secrets
# .pre-commit-config.yaml:
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
pre-commit install # installs hooks
# Now: git commit fails if secrets detected
# Scan git history for already-committed secrets:
trufflehog git file://. --only-verified
# or: git-secrets --scan-history
# Secret managers:
# HashiCorp Vault: centralized secret storage with dynamic credentials
vault kv put secret/app/db password=SuperSecret123
vault kv get secret/app/db
# Application reads at runtime, not from config file
# AWS Secrets Manager:
aws secretsmanager get-secret-value --secret-id prod/db/password
# Environment variables (minimal viable approach):
import os
DB_PASSWORD = os.environ['DB_PASSWORD'] # GOOD
# DB_PASSWORD = 'hardcoded' # BAD
# 12-factor app: config from environment
DevSecOps Pipeline
# Complete DevSecOps GitHub Actions pipeline:
name: Security Pipeline
on: [push, pull_request]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Semgrep SAST
uses: returntocorp/semgrep-action@v1
with: config: p/owasp-top-10
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: pip-audit
run: pip install pip-audit && pip-audit -r requirements.txt
- name: npm audit
run: npm audit --audit-level=high
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with: fetch-depth: 0 # full history for trufflehog
- name: TruffleHog
uses: trufflesecurity/trufflehog@main
with: only-verified: true
container-scan:
runs-on: ubuntu-latest
steps:
- name: Build image
run: docker build -t myapp:latest .
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:latest
exit-code: 1
severity: CRITICAL
Threat model the CyberLearn platform (or your own app): (1) draw a data flow diagram: browser, web server, database, cache, auth service, (2) identify trust boundaries: internet-to-server, server-to-DB, (3) apply STRIDE to each component — for the login endpoint: S=credential stuffing, T=session token tampering, R=no audit log, I=password in URL logs, D=no rate limiting, E=IDOR to other users, (4) rate each threat with CVSS, (5) propose mitigations for each — map to OWASP controls.
What is a trust boundary in threat modeling?
Integrate SAST into a Python project: (1) install Bandit: pip3 install bandit, (2) run: bandit -r . -ll (list medium+ issues), (3) introduce an intentional vulnerability: cursor.execute('SELECT * FROM users WHERE id=' + user_id) — SQL injection, (4) re-run Bandit: it should flag the SQL injection, (5) set up a pre-commit hook: pip3 install pre-commit, add bandit to .pre-commit-config.yaml, (6) commit the vulnerable code — the hook should block it.
What is the difference between SAST false positives and false negatives?
Audit dependencies for CVEs: (1) pip-audit your project's requirements.txt, (2) npm audit an old JavaScript project (create package.json with outdated packages: [email protected], [email protected]), (3) identify critical/high CVEs in the old packages, (4) generate an SBOM with Syft, (5) scan SBOM with Grype, (6) update vulnerable packages and re-scan, (7) set up Dependabot in a GitHub repository.
What is an SBOM and why is it required by US Executive Order 14028?