DevSecOps: Integrando Segurança em Cada Fase do Ciclo de Desenvolvimento
DevSecOps é mais que um buzzword — é uma transformação cultural e técnica que embute segurança desde o primeiro commit até o deployment em produção. Ao invés de tratar segurança como uma fase final de testes (model waterfall antiquado), DevSecOps distribui responsabilidades de segurança entre todas as equipes: desenvolvedores, operações e segurança trabalham em conjunto desde o início. O objetivo? Reduzir vulnerabilidades, acelerar delivery e criar um ambiente onde a segurança não é um obstáculo, mas parte natural do fluxo de trabalho.
Nesta aula, vamos explorar como integrar segurança em cada etapa do ciclo de vida, desde o desenvolvimento local até produção, com exemplos práticos que você pode aplicar imediatamente.
Fundamentos de DevSecOps: O Mindset
Princípios Essenciais
DevSecOps repousa em três pilares: automação, visibilidade e responsabilidade compartilhada. Automação elimina processos manuais propensos a erros e permite feedback rápido. Visibilidade significa logging, monitoramento e alertas contínuos para detectar anomalias. Responsabilidade compartilhada quebra silos — o desenvolvedor não pode dizer "não é meu problema" quando um código inseguro chega à produção.
A segurança tradicional é reativa: espera-se até encontrar um problema, então corrige-se. DevSecOps é proativo: previne problemas antes que causem dano. Isso exige mudança cultural. Equipes precisam entender que segurança acelerada o delivery (reduzindo incidentes caros), não o retarda.
Diferenças entre Abordagens Antigas e DevSecOps
Na abordagem legada, segurança entra no final: desenvolvimento → testes funcionais → penetration testing → produção. Leva meses, cria bottlenecks e vulnerabilidades escapam. Em DevSecOps, segurança é paralela: desenvolvimento com guardrails de segurança → testes automatizados de segurança em tempo real → produção com monitoramento contínuo. O feedback é semanal ou diário, não trimestral.
Segurança na Fase de Desenvolvimento
Análise Estática de Código (SAST)
Análise estática revisa código-fonte sem executá-lo, identificando padrões perigosos: SQL injection, hardcoded secrets, uso de funções inseguras. Ferramentas como SonarQube e Semgrep fazem isso automaticamente a cada commit. O desenvolvedor descobre problemas em segundos, não semanas depois.
Vamos implementar uma verificação básica usando Semgrep em um projeto Python. Semgrep é agnóstico de linguagem e detecta padrões seguindo regras YAML simples.
# .semgrep.yml - Exemplo de regra customizada
rules:
- id: hardcoded-sql-password
pattern-either:
- patterns:
- pattern: |
password = "..."
conn = $DATABASE.connect(..., password=password, ...)
- pattern: |
$DATABASE.connect(..., password="...", ...)
message: "Senha hardcoded detectada. Use variáveis de ambiente."
languages: [python]
severity: ERROR
- id: insecure-random
pattern: |
import random
...
random.randint(...)
message: "random.randint() é criptograficamente inseguro. Use secrets.randbelow()."
languages: [python]
severity: WARNING
Integre ao pipeline:
# .github/workflows/sast.yml (GitHub Actions)
name: SAST Analysis
on: [push, pull_request]
jobs:
semgrep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: returntocorp/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/cwe-top-25
p/security-audit
Quando alguém faz push, Semgrep roda automaticamente. Se encontra uma vulnerabilidade, bloqueia o merge até correção.
Dependency Scanning (OWASP Dependency-Check)
Código legítimo usando bibliotecas vulneráveis é um risco real. OWASP Dependency-Check varre suas dependências contra um banco de CVEs. Se uma lib tem vulnerability conhecida, você sabe imediatamente.
<!-- pom.xml (Java Maven) -->
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.4.2</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<failBuildOnCVSS>7.0</failBuildOnCVSS>
<!-- Falha build se CVSS >= 7 -->
</configuration>
</plugin>
</plugins>
Rode no CI:
# CI pipeline
mvn clean install org.owasp:dependency-check-maven:check
Secrets Management no Desenvolvimento
Credenciais hardcoded em código são um dos top 10 do OWASP. Use .env em desenvolvimento e variáveis de ambiente em produção. Ferramentas como git-secrets previnem commits acidentais.
# Instalar git-secrets
brew install git-secrets
# Configurar para repositório
cd seu-repo
git secrets --install
# Adicionar padrão customizado para detectar padrões AWS
git secrets --add 'AKIA[0-9A-Z]{16}'
# Fazer scan de toda história
git secrets --scan-history
# Ao tentar fazer commit com secret:
echo "aws_access_key_id=AKIAIOSFODNN7EXAMPLE" >> config.py
git add config.py
git commit -m "Add config"
# ❌ ERROR: Matched one or more blacklisted patterns
Automação de Testes de Segurança no Pipeline CI/CD
Dynamic Application Security Testing (DAST)
Enquanto SAST examina código-fonte, DAST testa a aplicação rodando. Simula ataques reais: SQL injection, XSS, CSRF. Ferramentas como OWASP ZAP e Burp Suite Community fazem isso automaticamente.
Vamos usar OWASP ZAP em um pipeline Docker:
# docker-compose.test.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- FLASK_ENV=test
zap:
image: owasp/zap2docker-stable:latest
depends_on:
- app
command: >
bash -c "sleep 10 &&
zap-cli quick-scan --self-signed
--spider-with-ajax
--recursive
http://app:8080
|| true"
volumes:
- ./zap-report:/zap/report
Aplicação Python simples para teste:
# app.py
from flask import Flask, request, render_template_string
import sqlite3
app = Flask(__name__)
@app.route('/search')
def search():
# ⚠️ VULNERÁVEL: SQL Injection
query = request.args.get('q', '')
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
# Em produção, ZAP detectaria: ?q=1' OR '1'='1
cursor.execute(f"SELECT * FROM users WHERE name='{query}'")
return str(cursor.fetchall())
@app.route('/xss')
def xss():
# ⚠️ VULNERÁVEL: XSS
user_input = request.args.get('name', 'Guest')
return render_template_string(f"<h1>Hello {user_input}</h1>")
# Em produção: ?name=<script>alert('pwned')</script>
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0')
ZAP detecta ambas vulnerabilidades e gera relatório. Em CI, você bloqueia merge se severidade alta for encontrada.
Container Scanning com Trivy
Imagens Docker podem conter vulnerabilidades no sistema operacional base ou nas bibliotecas instaladas. Trivy escaneia imagens rapidamente.
# Dockerfile com vulnerabilidades intencionais
FROM node:12-alpine
# Node 12 está deprecated, Trivy alertará
WORKDIR /app
COPY package.json .
RUN npm install lodash@4.17.20
# lodash 4.17.20 tem vulnerabilidades conhecidas
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
No pipeline:
#!/bin/bash
# scan-image.sh
IMAGE_NAME="myapp:latest"
docker build -t $IMAGE_NAME .
# Instalar Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Escanear imagem
trivy image --severity HIGH,CRITICAL $IMAGE_NAME
# Se encontrar vulnerabilidades críticas, falha
if trivy image --severity CRITICAL --exit-code 1 $IMAGE_NAME; then
echo "✅ Imagem segura"
docker push $IMAGE_NAME
else
echo "❌ Vulnerabilidades críticas detectadas"
exit 1
fi
Testes de Segurança Parametrizados com Pytest
Para aplicações que você controla, write explicit security tests:
# test_security.py
import pytest
from app import app
import re
@pytest.fixture
def client():
with app.test_client() as client:
yield client
def test_no_sql_injection(client):
"""Verifica se SQL injection é prevenido"""
response = client.get("/search?q=1' OR '1'='1")
assert response.status_code == 400 or "error" in response.data.lower()
def test_no_xss(client):
"""Verifica se XSS é prevenido"""
response = client.get("/greet?name=<script>alert('xss')</script>")
# Resposta deve escapar HTML
assert "<script>" not in response.data.decode()
assert "<script>" in response.data.decode()
def test_security_headers(client):
"""Verifica headers de segurança essenciais"""
response = client.get("/")
assert "X-Content-Type-Options" in response.headers
assert response.headers["X-Content-Type-Options"] == "nosniff"
assert "X-Frame-Options" in response.headers
def test_password_not_in_response(client):
"""Garante que dados sensíveis não vazam"""
response = client.get("/api/user/123")
assert "password" not in response.data.lower()
assert "secret" not in response.data.lower()
# Rodar com: pytest test_security.py -v
Segurança em Produção: Monitoramento e Resposta
Logging Centralizado e Auditing
Logs são a primeira linha de defesa em produção. Atacantes deixam rastros: múltiplas tentativas de login, acessos a endpoints admin, etc. Centralize logs em ferramentas como ELK Stack ou Splunk.
# filebeat.yml - Coleta logs do servidor
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
# Parsing de eventos suspeitos
processors:
- add_fields:
target: security
fields:
is_suspicious: false
- script:
lang: javascript
code: >
function process(event) {
var msg = event.Get("message");
if (msg.includes("SQL") || msg.includes("injection")) {
event.Put("security.is_suspicious", true);
event.Put("security.threat_level", "CRITICAL");
}
if (msg.match(/Failed password.*5 times/)) {
event.Put("security.is_suspicious", true);
event.Put("security.threat_level", "HIGH");
}
}
output.elasticsearch:
hosts: ["elasticsearch:9200"]
Queries Elasticsearch para alertas:
{
"query": {
"bool": {
"must": [
{ "term": { "security.is_suspicious": true } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
]
}
}
}
Runtime Application Self-Protection (RASP)
RASP monitora aplicação em tempo real e bloqueia ataques sem esperar por logs. Se detecta SQL injection, bloqueia a query. Se detecta path traversal, nega acesso. É segurança executada dentro do aplicativo.
# rasp_middleware.py - Implementação básica em Flask
import re
from functools import wraps
from flask import request, abort
DANGEROUS_PATTERNS = [
r"(\bOR\b.*1\s*=\s*1)", # SQL injection
r"(\.\./|\.\.\\)", # Path traversal
r"(<script|javascript:)", # XSS
]
def rasp_check(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# Verifica query parameters
for key, value in request.args.items():
for pattern in DANGEROUS_PATTERNS:
if re.search(pattern, value, re.IGNORECASE):
print(f"⚠️ RASP ALERT: {pattern} detected in {key}")
abort(403)
# Verifica método HTTP suspeito
if request.method not in ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']:
abort(403)
# Verifica tamanho excessivo de payload
if len(request.data) > 10 * 1024 * 1024: # 10MB
abort(413)
return f(*args, **kwargs)
return decorated_function
@app.route('/api/search')
@rasp_check
def protected_search():
return {"status": "ok"}
Em produção real, use RASP comercial (IastServer, Contrast, etc) ou open-source (ModSecurity).
Policies de Acesso e Zero Trust
Zero Trust: nunca confie por padrão, sempre verifique. Mesmo para tráfego interno. Implemente:
# network-policy.yaml - Kubernetes
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
spec:
podSelector:
matchLabels:
tier: api
ingress:
- from:
- podSelector:
matchLabels:
tier: frontend
ports:
- protocol: TCP
port: 8080
Bloqueia todo tráfego por padrão, permite apenas rotas definidas explicitamente.
Integrando Tudo: Um Pipeline DevSecOps Real
Aqui está um exemplo completo de pipeline que integra todas as práticas:
# .gitlab-ci.yml (GitLab CI, mas conceitos valem para GitHub/Jenkins)
stages:
- scan-secrets
- sast
- dependency-check
- build
- dast
- deploy
- monitor
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# 1. Detectar secrets
scan-secrets:
stage: scan-secrets
image: zricethezav/gitleaks:latest
script:
- gitleaks detect --source . --verbose
allow_failure: false
# 2. SAST com Semgrep
sast:
stage: sast
image: returntocorp/semgrep
script:
- semgrep --config=p/owasp-top-ten --config=p/cwe-top-25 --json --output=semgrep-report.json .
artifacts:
reports:
sast: semgrep-report.json
# 3. Verificar dependências
dependency-check:
stage: dependency-check
image: owasp/dependency-check:latest
script:
- /usr/share/dependency-check/bin/dependency-check.sh
--scan .
--format JSON
--project "MyApp"
--failOnCVSS 7.0
artifacts:
paths:
- dependency-check-report.json
# 4. Build e criar imagem
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $DOCKER_IMAGE .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $DOCKER_IMAGE
# 5. DAST
dast:
stage: dast
image: owasp/zap2docker-stable
services:
- name: $DOCKER_IMAGE
alias: app
script:
- sleep 10
- zap-cli quick-scan --self-signed http://app:8080
allow_failure: true
artifacts:
paths:
- zap-report.html
# 6. Deploy apenas se tudo passou
deploy:
stage: deploy
image: alpine:latest
script:
- echo "Deploying $DOCKER_IMAGE to production"
- apk add --no-cache curl
- curl -X POST https://our-k8s-cluster.com/deploy -d "image=$DOCKER_IMAGE"
only:
- main
when: on_success
# 7. Monitoramento contínuo
monitor:
stage: monitor
image: curlimages/curl:latest
script:
- curl -X POST https://monitoring.company.com/api/deploy
-H "Content-Type: application/json"
-d '{"version":"'$CI_COMMIT_SHA'","environment":"production"}'
only:
- main
Quando alguém faz push:
1. Gitleaks detecta secrets em 30s
2. Semgrep encontra vulnerabilidades em 1min
3. Dependency-check valida libs em 2min
4. Docker é built em 3min
5. ZAP testa a aplicação rodando em 5min
6. Se tudo passou, deploy automático para produção
7. Monitoramento começa imediatamente
Tempo total: ~15 minutos para feedback completo. Sem DevSecOps, levaria semanas com testes manuais.
Conclusão
Três pontos fundamentais do DevSecOps que você deve levar:
-
Segurança como Código: Use ferramentas de automação (SAST, DAST, scanning) para detectar 90% dos problemas antes de humanos. Isso não substitui code review, mas elimina a necessidade de caçar vulnerabilidades óbvias manualmente.
-
Feedback Rápido Muda Tudo: Quando um desenvolvedor descobre um SQL injection 30 segundos após fazer commit, ele corrige em minutos. Se descobre após 3 meses em produção, o custo é exponencialmente maior. DevSecOps reduz esse ciclo drasticamente.
-
Responsabilidade Compartilhada é Cultural: Não é sobre ferramentas. É sobre mentalidade. Desenvolvedores precisam pensar em segurança, security needs entender constraints de velocidade, e operações precisa monitorar continuamente. Silos são inimigos de DevSecOps.
Referências
- OWASP Top 10 2021 — Vulnerabilidades mais críticas em aplicações web
- DevSecOps Manifesto — Princípios fundamentais da prática
- CIS Controls — Framework de controles de segurança aplicáveis a qualquer organização
- Trivy Documentation — Guia completo de scanning de containers
- NIST Cybersecurity Framework — Padrão governamental para gestão de riscos de segurança