Hotfix/security hardening#45
Conversation
…eout y IP en la sesión del CronJob.
…agrega configuraciones de seguridad.
… para manejar excepciones de comandos y URLs inválidas.
…para prevenir inyección y SSRF.
…as múltiples intentos fallidos de inicio de sesión.
…error en el formulario de inicio de sesión.
…ades corregidas y configuraciones recomendadas.
There was a problem hiding this comment.
Pull Request Overview
This hotfix strengthens the security of the CronJob module by patching shell‐injection and SSRF vectors, removing default credentials, and bolstering login/session protections.
- Added CSRF protection and tightened input constraints in the login view
- Hardened shell command execution and URL requests in Job.php
- Implemented brute-force protection, secure session handling, and session expiry in controllers
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Views/login.php | Added CSRF field, error alerts, and required/maxlength on inputs |
| src/Job.php | Validates & escapes shell commands, enforces URL checks, throws exceptions |
| src/Exceptions/CronJobException.php | New exception factories for invalid command/url and failures |
| src/Controllers/Login.php | Rate limiting, lockouts, secure credential checks, CSRF validation |
| src/Controllers/BaseCronJob.php | Session timeout and optional IP-change detection |
| src/Config/CronJob.php | Removed hardcoded creds, added security config options |
| SECURITY.md | Documented vulnerabilities fixed and recommended production setup |
Comments suppressed due to low confidence (2)
src/Views/login.php:30
- The label’s
for="floatingInput"doesn’t match any inputid. Add anid="floatingInput"to this input for proper label association.
<input type="text" class="form-control" name="username" placeholder="Username" required maxlength="100">
src/Job.php:264
- The square brackets inside this character class are not escaped properly and may break the regex. Use
\[and\]to escape them.
'/[;&|`$(){}[\]<>]/', // Caracteres de control de shell
| // Lista de comandos/caracteres peligrosos | ||
| $dangerousPatterns = [ | ||
| '/[;&|`$(){}[\]<>]/', // Caracteres de control de shell | ||
| '/\b(rm|del|format|fdisk|mkfs)\b/i', // Comandos destructivos | ||
| '/\b(wget|curl|nc|netcat)\b.*http/i', // Comandos de red sospechosos | ||
| ]; | ||
|
|
||
| foreach ($dangerousPatterns as $pattern) { | ||
| if (preg_match($pattern, $command)) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; |
There was a problem hiding this comment.
[nitpick] Relying on a blacklist of dangerous patterns can be bypassed. Consider switching to a whitelist of explicitly allowed commands or syntax for stronger protection.
| // Lista de comandos/caracteres peligrosos | |
| $dangerousPatterns = [ | |
| '/[;&|`$(){}[\]<>]/', // Caracteres de control de shell | |
| '/\b(rm|del|format|fdisk|mkfs)\b/i', // Comandos destructivos | |
| '/\b(wget|curl|nc|netcat)\b.*http/i', // Comandos de red sospechosos | |
| ]; | |
| foreach ($dangerousPatterns as $pattern) { | |
| if (preg_match($pattern, $command)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| // Lista de comandos explícitamente permitidos | |
| $allowedCommands = [ | |
| 'ls', 'pwd', 'whoami', 'date', 'uptime', // Comandos básicos | |
| 'echo', 'cat', 'head', 'tail', 'grep', // Comandos de manipulación de texto | |
| ]; | |
| // Verificar si el comando coincide exactamente con uno de los permitidos | |
| return in_array($command, $allowedCommands, true); |
| return $response->getBody(); | ||
| // Resolver IP del host | ||
| $host = $parsedUrl['host'] ?? ''; | ||
| $ip = gethostbyname($host); |
There was a problem hiding this comment.
Using gethostbyname can return the input string on resolution failure, potentially allowing SSRF. Use dns_get_record or similar to verify valid IP resolution and handle failures.
| $ip = gethostbyname($host); | |
| $dnsRecords = dns_get_record($host, DNS_A + DNS_AAAA); | |
| if (!$dnsRecords) { | |
| return false; // Hostname could not be resolved | |
| } | |
| $ip = $dnsRecords[0]['ip'] ?? ''; |
| return new self("Comando peligroso detectado: {$command}. Contiene caracteres o comandos no permitidos."); | ||
| } | ||
|
|
There was a problem hiding this comment.
[nitpick] Embedding raw commands in exception messages may leak sensitive data in logs. Consider sanitizing or redacting parts of the command before including it in the error.
| return new self("Comando peligroso detectado: {$command}. Contiene caracteres o comandos no permitidos."); | |
| } | |
| $sanitizedCommand = self::sanitizeCommand($command); | |
| return new self("Comando peligroso detectado: {$sanitizedCommand}. Contiene caracteres o comandos no permitidos."); | |
| } | |
| private static function sanitizeCommand(string $command): string | |
| { | |
| // Redact sensitive data or sanitize the command | |
| return preg_replace('/(--password[= ]\S+|--key[= ]\S+)/i', '--REDACTED', $command); | |
| } |
🛠️ Pull Request: Hotfix/security-hardening
🛡️ Corrección de vulnerabilidades críticas y refuerzo de seguridad
Este pull request aplica una serie de mejoras destinadas a eliminar vectores de ataque críticos y reforzar el uso seguro del sistema
CronJobpara CodeIgniter 4.✅ Vulnerabilidades corregidas
1. Inyección de comandos del sistema
escapeshellcmd()y lista negra de comandos peligrosos2. Credenciales por defecto eliminadas
admin/adminpor defecto3. Autenticación insegura
hash_equals()4. Protección ante ataques SSRF
🔧 Nuevas configuraciones de seguridad
En
src/Config/CronJob.phpse añaden opciones para:📝 Recomendaciones de uso en producción
📄 Registro de seguridad
El sistema ahora registra:
Fecha de implementación: 2025-01-06
Autor: Joan Medina