From f8a3643ab92b64e93d5d11f0bbd801e73f6f21f6 Mon Sep 17 00:00:00 2001 From: pm Date: Sat, 13 Jun 2026 10:55:34 +0100 Subject: [PATCH] owasp zap config v13 --- backend/server.js | 64 +++++++++++++++++++++------------------------ frontend/index.html | 7 ++++- tests/core.test.js | 12 ++++++++- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/backend/server.js b/backend/server.js index abcaa8e..756a699 100644 --- a/backend/server.js +++ b/backend/server.js @@ -7,7 +7,6 @@ const app = express(); app.disable('x-powered-by'); - const PORT = process.env.PORT || 3000; app.use(cors()); @@ -17,21 +16,35 @@ app.use(express.urlencoded({ extended: true })); // Serve a pasta frontend app.use(express.static(path.join(__dirname, '../frontend'), { extensions: ['html'] })); -// Rotas das 4 páginas +// Rotas das 4 páginas estáticas app.get('/', (req, res) => res.sendFile(path.join(__dirname, '../frontend/index.html'))); app.get('/about', (req, res) => res.sendFile(path.join(__dirname, '../frontend/about.html'))); 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 VULNERÁVEL (Armadilha infalível para o OWASP ZAP) +// ========================================== +app.get('/api/search', (req, res) => { + const termo = req.query.q || ''; + // A vulnerabilidade crítica: devolver o input diretamente no HTML + res.send(` + + Resultados + +

Resultados para: ${termo}

+ Voltar + + + `); +}); -// Configuração do transporte de E-mail +// Configuração do transporte de E-mail (Mocks de teste vs Produção) let transporter; if (process.env.NODE_ENV === 'test') { - // Em teste, criamos um mock vazio para evitar erros transporter = { sendMail: jest.fn().mockResolvedValue({ messageId: 'test-id' }) }; } else { - // Em produção, usamos o transporter real transporter = nodemailer.createTransport({ host: 'mail.limpezascleanandcare.com', port: 465, @@ -44,24 +57,13 @@ if (process.env.NODE_ENV === 'test') { }); } - -// Endpoint do Formulário de Contacto (Com Recetor Dinâmico) -/*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.' }); - }*/ - +// Endpoint do Formulário de Contacto (Com a armadilha validada pelo Jest) 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 - // ========================================== + // Se faltarem dados, devolvemos HTML para simular XSS e bater com o teste unitário if (!email || !message) { - res.setHeader('Content-Type', 'text/html'); // Força o browser a interpretar como HTML + res.setHeader('Content-Type', 'text/html'); return res.status(400).send(`

Erro de Validação

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

@@ -70,52 +72,46 @@ app.post('/api/contact', async (req, res) => { } try { - // Construção do Email - Agora enviado para o e-mail inserido no formulário const mailOptions = { - from: '"Apex Solutions" ', // Remetente fixo válido - to: email, // RECETOR DINÂMICO (Vem diretamente do campo Email Address) + from: '"Apex Solutions" ', + to: email, subject: `Confirmation: We received your request, ${firstName}!`, html: `

Hello ${firstName} ${lastName},

- Thank you for reaching out to Apex Solutions. This is an automated confirmation to let you know that we have successfully received your inquiry. + Thank you for reaching out to Apex Solutions. This is an automated confirmation.

-

Summary of your submission:

Subject/Company: ${company || 'Not specified'}

"${message}"

-

- Our advisory team will review your details and get back to you within 24 business hours. + Our team will get back to you within 24 business hours.

-
-

- Best regards,
- Apex Solutions Corporate Team + Best regards,
Apex Solutions Corporate Team

` }; - // Envia o e-mail real const info = await transporter.sendMail(mailOptions); console.log(`[Email Sent Automatically to ${email}] Message ID: ${info.messageId}`); - res.status(200).json({ success: true, message: 'Thank you! A confirmation email has been dispatched to your address.' }); + res.status(200).json({ success: true, message: 'Thank you! A confirmation email has been dispatched.' }); } catch (error) { console.error(`[Email Error]:`, error); res.status(500).json({ error: 'Internal server error. Could not send confirmation email.' }); } }); + module.exports = { app, transporter }; -// Export the app for testing, but only listen if run directly + if (require.main === module) { app.listen(PORT, () => { console.log(`[Apex Server] Running on port ${PORT}`); }); -} +} \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index a992fd7..c2469ae 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -93,7 +93,12 @@ - +
+
+ + +
+

© 2026 Apex Solutions. All rights reserved.

diff --git a/tests/core.test.js b/tests/core.test.js index 18a6f8c..be55452 100644 --- a/tests/core.test.js +++ b/tests/core.test.js @@ -35,6 +35,16 @@ describe('Enterprise Application Flow & API Validation', () => { const response = await request(app).get('/invalid-admin-route'); expect(response.status).toBe(404); }); + + // NOVO TESTE: Valida a nossa armadilha para o OWASP ZAP (corrigido para /api/search) + it('Should reflect the search query in the HTML response (/api/search) - Vulnerable to XSS', async () => { + const maliciousPayload = ''; + const response = await request(app).get(`/api/search?q=${maliciousPayload}`); + + expect(response.status).toBe(200); + // Verifica se o payload é refletido exatamente como entrou (confirmando a vulnerabilidade) + expect(response.text).toContain(`Resultados para: ${maliciousPayload}`); + }); }); // ========================================== @@ -58,7 +68,7 @@ describe('Enterprise Application Flow & API Validation', () => { // 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) + expect(response.text).toContain('John'); // Garante que o input foi refletido na página }); it('Should process request, return 200 OK, and invoke SMTP transporter with valid data', async () => { -- 2.52.0