Este repositório demonstra como integrar ferramentas de análise estática (SAST) e análise dinâmica (DAST) em uma pipeline CI/CD usando GitHub Actions.
Os principais objetivo de implementações desse tipo são:
- Identificar vulnerabilidades na codebase antes que possam ser exploradas em produção;
- Melhorar a postura geral de segurança da aplicação;
- Automatizar certas verificações de segurança para agilizar o processo de desenvolvimento e dar escala à times de segurança.
O workflow do GitHub Actions é estruturada da seguinte forma:
-
Eventos
- O workflow é disparado nos eventos de
push
epull request
no repositório da aplicação. Também é possível executar sob demanda quando o dono do repositório solicitar.
- O workflow é disparado nos eventos de
-
Jobs
- Build: O primeiro job faz o build da aplicação.
- SAST: Após a conclusão do job de build, os testes de SAST são executados. Este job analisa o código estaticamente.
- DAST: Uma vez que o job SAST é concluído com sucesso, a verificação DAST é executada para identificar vulnerabilidades em tempo de execução. Por se tratar de um teste dinâmico, scans DAST geralmente levam um pouco mais de tempo para executar que scans SAST.
Vale ressaltar que não foram configurados rulesets customizados. Os scans estão rodando com suas configurações padrão e, portanato, não estão 100% otimizados.
- SAST :: Semgrep
- Objetivo: Ferramentas SAST analisam o código em busca de vulnerabilidades sem executar a aplicação. Elas ajudam a identificar problemas diversos (ex.: SQLi, XSS, Clickjacking, etc) no código.
- Implementação: A ferramenta SAST (Semgrep) está integrada no workflow do GitHub Actions. O workflow ignora qualquer PR aberto pelo DependaBot.
sast:
name: sast/semgrep
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
if: (github.actor != 'dependabot[bot]')
permissions:
security-events: write
actions: read
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Perform Semgrep Analysis
run: semgrep scan -q --sarif --config auto . > semgrep-results.sarif
- name: Save SARIF results as artifact
uses: actions/upload-artifact@v3
with:
name: semgrep-scan-results
path: semgrep-results.sarif
- name: Upload SARIF result to the GitHub Security Dashboard
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: semgrep-results.sarif
if: always()
- DAST :: ZAP
- Objetivo: Ferramentas DAST testam a aplicação em tempo de execução em busca de vulnerabilidades, simulando ataques. Elas identificam falhas como problemas de authZ e authN, gerenciamento inadequado de sessões e configurações inseguras no ambiente.
- Implementação: A ferramenta DAST (ZAP) também está integrada no workflow do GitHub Actions. Ela analisa a aplicação em busca de vulnerabilidades, e os resultados são escritos em um arquivo JSON.
dast:
name: dast/zap
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download OWASP ZAP Proxy
run: |
wget https://github.com/zaproxy/zaproxy/releases/download/v2.15.0/ZAP_2.15.0_Crossplatform.zip
unzip ZAP_2.15.0_Crossplatform.zip
cd ZAP_2.15.0
- name: Build Image
run: docker compose build
- name: Launch app
run: docker compose up --detach
- name: Check containers
run: docker ps
- name: Wait for app to be ready
run: |
until curl -s http://localhost:5002; do
echo "Waiting for the app to start..."
sleep 5
done
- name: Run OWASP ZAP Scan
env:
ZAP_URL: 'http://localhost:5002'
run: |
cd ZAP_2.15.0
./zap.sh -cmd -quickurl "$ZAP_URL" -quickout /home/runner/work/vampi-sectests/vampi-sectests/ZAP_2.15.0/zap-proxy-report.json
- name: Upload ZAP Report
uses: actions/upload-artifact@v4
with:
name: zap-proxy-report
path: /home/runner/work/vampi-sectests/vampi-sectests/ZAP_2.15.0/zap-proxy-report.json
Os insumos dos scans são:
- Para o SAST, devido ao Semgrep servir os resultados de scan em formato SARIF, o GitHub consegue importar esses dados e organiza-los na aba de Security do repositório. Um exemplo:
- No caso do DAST, como o ZAP não tem suporte para resultados em SARIF, o GitHub não consegue fazer esse tratamento. É possível fazer o download do JSON com as informações através dos logs das Actions bem-sucedidas. Para facilitar, esse é um output de um dos scans feitos na aplicação:
{
"@programName": "ZAP",
"@version": "2.15.0",
"@generated": "Thu, 3 Oct 2024 18:25:37",
"site":[
{
"@name": "http://localhost:5002",
"@host": "localhost",
"@port": "5002",
"@ssl": "false",
"alerts": [
{
"pluginid": "10036",
"alertRef": "10036",
"alert": "Server Leaks Version Information via \"Server\" HTTP Response Header Field",
"name": "Server Leaks Version Information via \"Server\" HTTP Response Header Field",
"riskcode": "1",
"confidence": "3",
"riskdesc": "Low (High)",
"desc": "<p>The web/application server is leaking version information via the \"Server\" HTTP response header. Access to such information may facilitate attackers identifying other vulnerabilities your web/application server is subject to.</p>",
"instances":[
{
"uri": "http://localhost:5002",
"method": "GET",
"param": "",
"attack": "",
"evidence": "Werkzeug/2.2.3 Python/3.11.10",
"otherinfo": ""
},
{
"uri": "http://localhost:5002/robots.txt",
"method": "GET",
"param": "",
"attack": "",
"evidence": "Werkzeug/2.2.3 Python/3.11.10",
"otherinfo": ""
},
{
"uri": "http://localhost:5002/sitemap.xml",
"method": "GET",
"param": "",
"attack": "",
"evidence": "Werkzeug/2.2.3 Python/3.11.10",
"otherinfo": ""
}
],
"count": "3",
"solution": "<p>Ensure that your web server, application server, load balancer, etc. is configured to suppress the \"Server\" header or provide generic details.</p>",
"otherinfo": "",
"reference": "<p>https://httpd.apache.org/docs/current/mod/core.html#servertokens</p><p>https://learn.microsoft.com/en-us/previous-versions/msp-n-p/ff648552(v=pandp.10)</p><p>https://www.troyhunt.com/shhh-dont-let-your-response-headers/</p>",
"cweid": "200",
"wascid": "13",
"sourceid": "6"
},
{
"pluginid": "10021",
"alertRef": "10021",
"alert": "X-Content-Type-Options Header Missing",
"name": "X-Content-Type-Options Header Missing",
"riskcode": "1",
"confidence": "2",
"riskdesc": "Low (Medium)",
"desc": "<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing.</p>",
"instances":[
{
"uri": "http://localhost:5002",
"method": "GET",
"param": "x-content-type-options",
"attack": "",
"evidence": "",
"otherinfo": "This issue still applies to error type pages (401, 403, 500, etc.) as those pages are often still affected by injection issues, in which case there is still concern for browsers sniffing pages away from their actual content type.\nAt \"High\" threshold this scan rule will not alert on client or server error responses."
}
],
"count": "1",
"solution": "<p>Ensure that the application/web server sets the Content-Type header appropriately, and that it sets the X-Content-Type-Options header to 'nosniff' for all web pages.</p><p>If possible, ensure that the end user uses a standards-compliant and modern web browser that does not perform MIME-sniffing at all, or that can be directed by the web application/web server to not perform MIME-sniffing.</p>",
"otherinfo": "<p>This issue still applies to error type pages (401, 403, 500, etc.) as those pages are often still affected by injection issues, in which case there is still concern for browsers sniffing pages away from their actual content type.</p><p>At \"High\" threshold this scan rule will not alert on client or server error responses.</p>",
"reference": "<p>https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/gg622941(v=vs.85)</p><p>https://owasp.org/www-community/Security_Headers</p>",
"cweid": "693",
"wascid": "15",
"sourceid": "6"
}
]
}
]
}