security: blindaje contra ejecucion de scripts RCE, Stored XSS, MIME sniffing, Path Traversal y DoS
This commit is contained in:
@@ -3,12 +3,14 @@ package main
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"app_compartir/internal/cleaner"
|
||||
"app_compartir/internal/db"
|
||||
"app_compartir/internal/models"
|
||||
"app_compartir/internal/storage"
|
||||
)
|
||||
|
||||
func TestGuestExpirationAndRegisteredPermanence(t *testing.T) {
|
||||
@@ -132,3 +134,78 @@ func TestGuestExpirationAndRegisteredPermanence(t *testing.T) {
|
||||
|
||||
t.Log("✅ Test completado con éxito: Solo los datos de invitado caducan en 24h; los de usuarios registrados son permanentes.")
|
||||
}
|
||||
|
||||
func TestSecurityProtections(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "test_security_*")
|
||||
if err != nil {
|
||||
t.Fatalf("error creando tmpDir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
uploadDir := filepath.Join(tmpDir, "uploads")
|
||||
|
||||
// 1. Probar Sanitización de Nombres (Path Traversal)
|
||||
traversalTests := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"../../../../etc/passwd", "etc_passwd"},
|
||||
{"..\\..\\windows\\system32\\cmd.exe", "cmd.exe"},
|
||||
{"test/../../shell.php", "shell.php"},
|
||||
{"../../../.htaccess", "_.htaccess"},
|
||||
}
|
||||
for _, tc := range traversalTests {
|
||||
sanitized := storage.SanitizeFilename(tc.input)
|
||||
if strings.Contains(sanitized, "/") || strings.Contains(sanitized, "\\") || strings.Contains(sanitized, "..") {
|
||||
t.Fatalf("Fallo en sanitización de path traversal para %s: resultado=%s", tc.input, sanitized)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Probar Detección de MIME Types Peligrosos (Neutralización de XSS y Scripts)
|
||||
dangerousMimes := []struct {
|
||||
filename string
|
||||
forbidden string
|
||||
expected string
|
||||
}{
|
||||
{"shell.php", "application/x-httpd-php", "text/plain; charset=utf-8"},
|
||||
{"exploit.phtml", "text/html", "text/plain; charset=utf-8"},
|
||||
{"malicious.html", "text/html", "text/plain; charset=utf-8"},
|
||||
{"test.xhtml", "text/html", "text/plain; charset=utf-8"},
|
||||
{"script.sh", "application/x-sh", "text/plain; charset=utf-8"},
|
||||
}
|
||||
for _, tc := range dangerousMimes {
|
||||
m := storage.DetectMimeType(tc.filename, nil)
|
||||
if m == tc.forbidden || strings.HasPrefix(m, "text/html") {
|
||||
t.Fatalf("MIME peligroso no neutralizado para %s: obtenido %s (prohibido %s)", tc.filename, m, tc.forbidden)
|
||||
}
|
||||
if m != tc.expected {
|
||||
t.Fatalf("MIME esperado %s para %s, obtenido %s", tc.expected, tc.filename, m)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Probar Guardado Seguro en Disco (Permisos no ejecutables y .htaccess preventivo)
|
||||
sampleContent := strings.NewReader("<?php echo 'hacked'; ?>")
|
||||
storedFile, _, err := storage.SaveFile(uploadDir, "secslug", "shell.php", sampleContent)
|
||||
if err != nil {
|
||||
t.Fatalf("error guardando archivo seguro: %v", err)
|
||||
}
|
||||
|
||||
// Verificar permisos en disco (NO ejecutable)
|
||||
destPath := filepath.Join(uploadDir, storedFile)
|
||||
fi, err := os.Stat(destPath)
|
||||
if err != nil {
|
||||
t.Fatalf("error comprobando archivo guardado: %v", err)
|
||||
}
|
||||
mode := fi.Mode().Perm()
|
||||
if mode&0111 != 0 {
|
||||
t.Fatalf("El archivo guardado tiene permisos de ejecución: %o", mode)
|
||||
}
|
||||
|
||||
// Verificar existencia de .htaccess preventivo
|
||||
htaccessPath := filepath.Join(uploadDir, ".htaccess")
|
||||
if _, err := os.Stat(htaccessPath); os.IsNotExist(err) {
|
||||
t.Fatalf(".htaccess preventivo no fue creado en uploadDir")
|
||||
}
|
||||
|
||||
t.Log("✅ Test completado con éxito: Protecciones de seguridad activas (sin path traversal, scripts neutralizados a texto plano y archivos no ejecutables).")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user