From 5805011296bd1e01c828ded828d879feb282ca23 Mon Sep 17 00:00:00 2001 From: pm Date: Sat, 13 Jun 2026 10:25:25 +0100 Subject: [PATCH 1/2] owasp zap config v9 --- .gitea/workflows/deploy.yml | 12 ++++++----- backend/server.js | 31 ++++++++++++++++------------- zap-baseline.conf => zap-rules.conf | 0 3 files changed, 24 insertions(+), 19 deletions(-) rename zap-baseline.conf => zap-rules.conf (100%) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 9b43079..0109dda 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -62,17 +62,19 @@ jobs: mkdir -p qatests docker volume create zap-data - # A MAGIA ACONTECE AQUI: Escrevemos o ficheiro de configuração diretamente no volume! - docker run --rm -v zap-data:/zap/wrk alpine sh -c 'echo "FAIL_ON_SEVERITY: HIGH" > /zap/wrk/zap-baseline.conf' + # Mudei o nome para zap-rules.conf (já não estamos a fazer baseline) + docker run --rm -v zap-data:/zap/wrk alpine sh -c 'echo "FAIL_ON_SEVERITY: HIGH" > /zap/wrk/zap-rules.conf' - echo ">>> 4. Executar OWASP ZAP..." + echo ">>> 4. Executar OWASP ZAP (FULL SCAN + AJAX SPIDER)..." + # AQUI: zap-full-scan.py em vez de zap-baseline.py! docker run --user root --name zap-scanner \ --network zap-net \ -v zap-data:/zap/wrk/:rw \ - -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py \ + -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py \ -t http://apex-sandbox:3000 \ -r report.html \ - -I -c zap-baseline.conf || true + -j \ + -I -c zap-rules.conf || true echo ">>> 5. Recolher o relatório HTML..." docker cp zap-scanner:/zap/wrk/report.html qatests/report.html || true diff --git a/backend/server.js b/backend/server.js index 029f8e0..abcaa8e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -23,19 +23,6 @@ app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/a app.get('/careers', (req, res) => res.sendFile(path.join(__dirname, '../frontend/careers.html'))); app.get('/contact', (req, res) => res.sendFile(path.join(__dirname, '../frontend/contact.html'))); -// Rota de Pesquisa Vulnerável a Reflected XSS (Armadilha para o OWASP ZAP) -app.get('/api/search', (req, res) => { - const termoPesquisa = req.query.q || ''; - // A vulnerabilidade: devolver o input diretamente para o navegador como HTML - res.send(` - - -

Resultados da pesquisa para: ${termoPesquisa}

-

Nenhum resultado encontrado.

- - - `); -}); // Configuração do transporte de E-mail let transporter; @@ -59,11 +46,27 @@ if (process.env.NODE_ENV === 'test') { // Endpoint do Formulário de Contacto (Com Recetor Dinâmico) -app.post('/api/contact', async (req, res) => { +/*app.post('/api/contact', async (req, res) => { const { firstName, lastName, email, company, message } = req.body; if (!email || !message) { return res.status(400).json({ error: 'Email and message are required.' }); + }*/ + +app.post('/api/contact', async (req, res) => { + const { firstName, lastName, email, company, message } = req.body; + + // ========================================== + // ARMADILHA PARA O ZAP (Reflected XSS) + // Se faltarem dados, devolvemos o input diretamente como HTML + // ========================================== + if (!email || !message) { + res.setHeader('Content-Type', 'text/html'); // Força o browser a interpretar como HTML + return res.status(400).send(` +

Erro de Validação

+

Os campos Email e Mensagem são obrigatórios.

+

Nome recebido: ${firstName}

+ `); } try { diff --git a/zap-baseline.conf b/zap-rules.conf similarity index 100% rename from zap-baseline.conf rename to zap-rules.conf From 7c7a2efd615773a5e5bd0a95bc8117c9fd74754a Mon Sep 17 00:00:00 2001 From: pm Date: Sat, 13 Jun 2026 10:29:03 +0100 Subject: [PATCH 2/2] owasp zap config v10 --- tests/core.test.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/core.test.js b/tests/core.test.js index 3a94203..18a6f8c 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -52,10 +52,16 @@ describe('Enterprise Application Flow & API Validation', () => { const response = await request(app).post('/api/contact').send(invalidPayload); expect(response.status).toBe(400); - expect(response.body).toHaveProperty('error', 'Email and message are required.'); + + // ========================================== + // CORREÇÃO DEVSECOPS: O servidor agora devolve HTML para a armadilha XSS! + // Lemos o response.text (HTML) em vez do response.body (JSON) + // ========================================== + expect(response.text).toContain('Erro de Validação'); + expect(response.text).toContain('John'); // Garante que o input foi refletido na página (a vulnerabilidade XSS) }); -it('Should process request, return 200 OK, and invoke SMTP transporter with valid data', async () => { + it('Should process request, return 200 OK, and invoke SMTP transporter with valid data', async () => { const validPayload = { firstName: 'Jane', lastName: 'Doe', @@ -70,7 +76,6 @@ it('Should process request, return 200 OK, and invoke SMTP transporter with vali expect(response.status).toBe(200); // Validate Business Logic: Verifica o objeto 'transporter' que veio do server.js - // Como este objeto é o que injetámos no server, ele já é o mock! expect(transporter.sendMail).toHaveBeenCalledTimes(1); }); });