Introducción a la Seguridad Web
La seguridad en el desarrollo de módulos para Perfex CRM es crítica. Un módulo vulnerable puede comprometer todo el sistema, exponiendo datos sensibles de clientes y la empresa. En este artículo cubriremos las tres vulnerabilidades más comunes según OWASP.
🔒 Las 3 Amenazas Principales
- CSRF - Cross-Site Request Forgery
- XSS - Cross-Site Scripting
- SQL Injection - Inyección SQL
1. CSRF - Cross-Site Request Forgery
CSRF ocurre cuando un atacante engaña a un usuario autenticado para que ejecute acciones no deseadas. Perfex CRM incluye protección CSRF por defecto, pero debes usarla correctamente.
Cómo Funciona un Ataque CSRF
Un atacante crea una página maliciosa que envía un formulario a tu aplicación. Si el usuario tiene sesión activa, la acción se ejecuta sin su conocimiento.
❌ Vulnerable
// JavaScript sin token CSRF
$.post('/admin/modulo/delete', {
id: 123
});
✅ Protegido
// Incluye token CSRF
$.post(admin_url + 'modulo/delete', {
...csrfData,
id: 123
});
Implementación Correcta
// En JavaScript, el objeto csrfData está disponible globalmente
$.ajax({
url: admin_url + 'mi_modulo/guardar',
type: 'POST',
data: {
[csrfData.token_name]: csrfData.hash, // Token CSRF
nombre: $('#nombre').val(),
descripcion: $('#descripcion').val()
},
success: function(response) {
// Manejar respuesta
}
});
// Forma abreviada usando spread operator
$.post(admin_url + 'mi_modulo/guardar', {
...csrfData,
nombre: 'valor'
});
💡 En Formularios HTML
Perfex añade automáticamente el token CSRF a los formularios creados con form_open(). Nunca uses <form> directamente.
2. XSS - Cross-Site Scripting
XSS permite a un atacante inyectar scripts maliciosos que se ejecutan en el navegador de otros usuarios. Puede robar sesiones, redirigir a sitios maliciosos o modificar el contenido de la página.
Tipos de XSS
- Stored XSS: El script se almacena en la base de datos
- Reflected XSS: El script viene en la URL
- DOM XSS: El script manipula el DOM directamente
❌ Vulnerable
<!-- Sin escapar -->
<p><?php echo $usuario->nombre; ?></p>
// Si nombre = "<script>alert('XSS')</script>"
// El script se ejecutará
✅ Protegido
<!-- Escapado correctamente -->
<p><?php echo html_escape($usuario->nombre); ?></p>
// El script se mostrará como texto
// <script>alert('XSS')</script>
Funciones de Escape en Perfex
// Para HTML
echo html_escape($input);
// Para atributos HTML
<input value="<?php echo html_escape($valor); ?>">
// Para URLs
<a href="<?php echo htmlspecialchars($url, ENT_QUOTES, 'UTF-8'); ?>">
// Para JavaScript (en JSON)
<script>
var data = <?php echo json_encode($data); ?>;
</script>
⚠️ Regla de Oro
Nunca confíes en datos del usuario. Escapa TODO lo que venga del exterior antes de mostrarlo: parámetros GET/POST, datos de BD, cookies, headers HTTP.
3. SQL Injection
SQL Injection ocurre cuando datos del usuario se insertan directamente en queries SQL sin sanitizar. El atacante puede leer, modificar o eliminar toda la base de datos.
❌ Vulnerable
// Concatenación directa
$id = $_GET['id'];
$query = "SELECT * FROM users
WHERE id = " . $id;
$this->db->query($query);
// Si id = "1 OR 1=1"
// Devuelve TODOS los usuarios
✅ Protegido
// Query Builder de CodeIgniter
$id = $this->input->get('id');
$this->db
->where('id', $id)
->get(db_prefix() . 'users');
// CodeIgniter escapa automáticamente
// Query: WHERE id = '1 OR 1=1'
Mejores Prácticas
// 1. SIEMPRE usa Query Builder
$this->db
->select('id, nombre, email')
->from(db_prefix() . 'clientes')
->where('activo', 1)
->where('id', $id)
->get();
// 2. Si necesitas query raw, usa bindings
$this->db->query(
"SELECT * FROM " . db_prefix() . "clientes WHERE email = ?",
[$email]
);
// 3. Para LIKE, usa escape_like_str()
$busqueda = $this->db->escape_like_str($input);
$this->db->like('nombre', $busqueda);
// 4. Valida tipos de datos
$id = (int) $this->input->get('id'); // Fuerza integer
Resumen: Checklist de Seguridad
✅ Lista de Verificación
CSRF:
□ Incluir csrfData en todas las peticiones AJAX
□ Usar form_open() en lugar de <form>
XSS:
□ Usar html_escape() en todas las salidas
□ Usar json_encode() para datos JavaScript
□ Validar y sanitizar inputs
SQL Injection:
□ Usar Query Builder siempre
□ Usar bindings para queries raw
□ Validar tipos de datos
□ Usar db_prefix() en nombres de tablas