security: fix 3 medium-severity vulnerabilities (Fase 3 partial)

MEDIUM-SEVERITY FIXES:

1. Mock Data em Produção (Vulnerabilidade 3.2)
   - Mock data apenas em desenvolvimento (import.meta.env.DEV)
   - Produção mostra erro claro: "Não foi possível carregar os dados"
   - Estado de erro com UI para retry
   - Import AlertCircle icon

2. Tipo 'any' em Catch Blocks (Vulnerabilidade 3.4 - partial)
   - api/routes/wp-monitor.ts: catch (error: unknown)
   - Type guard: error instanceof Error
   - Mensagens seguras sem vazamento de stack trace

3. Algoritmos SSH Legacy (Vulnerabilidade 3.6)
   - Adicionados: curve25519-sha256, curve25519-sha256@libssh.org
   - Removidos: diffie-hellman-group14-sha1 (legacy)
   - Removidos: diffie-hellman-group1-sha1 (INSEGURO)
   - Mantidos apenas SHA256+ algorithms

FILES CHANGED:
- src/App.tsx - Error state + mock data apenas em dev
- api/routes/wp-monitor.ts - Tipos unknown em catch
- api/services/server-metrics.ts - Algoritmos SSH modernos

PROGRESS:
- Vulnerabilidade 3.2:  FIXED
- Vulnerabilidade 3.4: 🔄 IN PROGRESS (2/10 files)
- Vulnerabilidade 3.6:  FIXED

Related: AUDIT-REPORT.md vulnerabilities 3.2, 3.4, 3.6

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 04:17:36 +00:00
parent f1756829af
commit b001d77a1f
3 changed files with 51 additions and 10 deletions

View File

@@ -58,9 +58,10 @@ router.get('/', validateApiKey, async (req: Request, res: Response) => {
total: result.length, total: result.length,
timestamp: new Date().toISOString() timestamp: new Date().toISOString()
}) })
} catch (error) { } catch (error: unknown) {
console.error('WP Monitor GET error:', error) const message = error instanceof Error ? error.message : 'Unknown error'
res.status(500).json({ error: 'Database error', message: (error as Error).message }) console.error('WP Monitor GET error:', message)
res.status(500).json({ error: 'Database error', message })
} }
}) })
@@ -105,9 +106,10 @@ router.post('/', validateApiKey, validateRequest(wpMonitorSchema), async (req: R
status, status,
timestamp: new Date().toISOString() timestamp: new Date().toISOString()
}) })
} catch (error) { } catch (error: unknown) {
console.error('WP Monitor POST error:', error) const message = error instanceof Error ? error.message : 'Unknown error'
res.status(500).json({ error: 'Database error', message: (error as Error).message }) console.error('WP Monitor POST error:', message)
res.status(500).json({ error: 'Database error', message })
} }
}) })

View File

@@ -136,13 +136,15 @@ function executeSSH(server: SSHServer, command: string): Promise<string> {
readyTimeout: 15000, readyTimeout: 15000,
algorithms: { algorithms: {
kex: [ kex: [
// Algoritmos modernos (Vulnerabilidade 3.6)
'curve25519-sha256',
'curve25519-sha256@libssh.org',
'ecdh-sha2-nistp256', 'ecdh-sha2-nistp256',
'ecdh-sha2-nistp384', 'ecdh-sha2-nistp384',
'ecdh-sha2-nistp521', 'ecdh-sha2-nistp521',
'diffie-hellman-group-exchange-sha256', 'diffie-hellman-group-exchange-sha256',
'diffie-hellman-group14-sha256', 'diffie-hellman-group14-sha256'
'diffie-hellman-group14-sha1', // REMOVIDOS (inseguros): diffie-hellman-group14-sha1, diffie-hellman-group1-sha1
'diffie-hellman-group1-sha1'
] ]
} }
}) })

View File

@@ -4,6 +4,7 @@ import {
Calendar, Calendar,
CalendarDays, CalendarDays,
AlertTriangle, AlertTriangle,
AlertCircle,
Clock, Clock,
Zap, Zap,
RefreshCw, RefreshCw,
@@ -420,6 +421,7 @@ function App() {
const [data, setData] = useState<DashboardData | null>(null) const [data, setData] = useState<DashboardData | null>(null)
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [refreshing, setRefreshing] = useState(false) const [refreshing, setRefreshing] = useState(false)
const [error, setError] = useState<string | null>(null)
const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const fetchData = useCallback(async () => { const fetchData = useCallback(async () => {
@@ -431,7 +433,13 @@ function App() {
setData(json) setData(json)
} catch (error) { } catch (error) {
console.error('Failed to fetch dashboard data:', error) console.error('Failed to fetch dashboard data:', error)
setData(getMockData())
// Mock data apenas em desenvolvimento (Vulnerabilidade 3.2)
if (import.meta.env.DEV) {
setData(getMockData())
} else {
setError('Não foi possível carregar os dados. Tente novamente.')
}
} finally { } finally {
setLoading(false) setLoading(false)
setRefreshing(false) setRefreshing(false)
@@ -470,6 +478,35 @@ function App() {
) )
} }
// Error state (Vulnerabilidade 3.2)
if (error) {
return (
<div className="min-h-screen bg-mesh flex items-center justify-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="text-center max-w-md mx-auto px-6"
>
<div className="w-20 h-20 rounded-2xl bg-red-500/10 flex items-center justify-center mx-auto mb-6 border border-red-500/20">
<AlertCircle className="w-10 h-10 text-red-500" />
</div>
<h2 className="text-xl font-semibold text-white mb-2">Erro ao Carregar</h2>
<p className="text-zinc-400 mb-6">{error}</p>
<button
onClick={() => {
setError(null)
setLoading(true)
fetchData()
}}
className="px-6 py-3 bg-brand-500 hover:bg-brand-600 text-white rounded-xl transition-colors"
>
Tentar Novamente
</button>
</motion.div>
</div>
)
}
if (!data) return null if (!data) return null
return ( return (