Definición
Los métodos seguros son métodos HTTP que están definidos para ser de solo lectura - recuperan información sin causar efectos secundarios en el servidor. Cuando haces una petición segura, el estado del servidor permanece sin cambios. Los cuatro métodos seguros en HTTP son GET, HEAD, OPTIONS y TRACE. Estos métodos están garantizados para ser “seguros de reintentar” porque no modifican datos, crean recursos ni desencadenan acciones.
El principio clave es que los clientes (navegadores, apps, intermediarios como proxies y cachés) pueden llamar métodos seguros libremente sin preocuparse por consecuencias. Puedes refrescar una página web (enviando peticiones GET) 100 veces, y no cambiará nada en el servidor. Esta predictibilidad permite almacenamiento en caché agresivo, precarga y rastreo automatizado.
Es importante notar que “seguro” se refiere a la semántica HTTP, no a la implementación. Una API mal diseñada podría usar GET para eliminar datos o enviar emails, violando el contrato de seguridad. Pero según la especificación HTTP, los métodos seguros nunca deberían alterar el estado del servidor. Este contrato es lo que hace la web escalable - las cachés y proxies pueden almacenar y reusar respuestas de métodos seguros sin permiso.
Ejemplo
GET - Recuperar Recurso: GET /api/products/123 obtiene datos del producto. Llamarlo una vez, diez veces o un millón de veces no cambia el producto. Los navegadores almacenan en caché respuestas GET, las CDNs las guardan, los motores de búsqueda las rastrean - todo porque GET es seguro.
HEAD - Verificar Metadatos del Recurso: HEAD /api/files/photo.jpg devuelve solo las cabeceras (Content-Type, Content-Length, Last-Modified) sin el cuerpo del archivo. Se usa para verificar si un archivo existe o ha sido actualizado sin descargarlo. Seguro de llamar repetidamente para monitorear cambios.
OPTIONS - Descubrir Capacidades: OPTIONS /api/users devuelve métodos HTTP permitidos (GET, POST, PUT, DELETE) y cabeceras CORS. Los navegadores usan peticiones preflight OPTIONS automáticamente. Es seguro porque solo describe qué es posible sin hacer nada.
TRACE - Loopback Diagnóstico: TRACE /api/debug devuelve la petición tal como fue recibida por el servidor, útil para depurar proxies e intermediarios. Raramente usado en la práctica pero definido como seguro porque no modifica estado.
Refresco del Navegador Web: Cuando presionas F5 para refrescar una página web, el navegador envía peticiones GET para el HTML, CSS, JavaScript e imágenes. Esto es seguro - refrescar no envía formularios, crea cuentas ni cobra tarjetas de crédito. La página se ve igual después del refresco.
Rastreo de Motores de Búsqueda: El rastreador de Google sigue enlaces y envía millones de peticiones GET diariamente. Estas deben ser seguras - Google rastreando tu sitio web no debería eliminar datos, desencadenar compras ni enviar emails. Por eso los rastreadores solo siguen métodos seguros.
Caché de CDN: Cloudflare almacena en caché respuestas GET de tu API. Cuando un usuario en Tokio solicita /api/products, Cloudflare sirve la respuesta almacenada desde un servidor cercano. Esto solo funciona porque GET es seguro - la respuesta almacenada está garantizada para ser válida ya que la petición no cambiará el estado del servidor.
Analogía
Leer un Libro: Cuando lees un libro, no cambias su contenido. Puedes leer la misma página 100 veces - permanece igual. GET es como leer - seguro, no destructivo, repetible.
Consultar el Saldo Bancario: Usar un cajero automático para consultar tu saldo es una operación segura. Puedes consultarlo 10 veces seguidas - tu saldo no cambia por consultarlo. Esto es como HEAD o GET - recuperar información sin modificación.
Mirar Escaparates: Caminar frente a una tienda y mirar el escaparate es seguro. No estás comprando nada, solo mirando. Puedes pasar frente al mismo escaparate múltiples veces sin consecuencia. Los métodos HTTP seguros son como mirar escaparates de datos.
Búsqueda en Catálogo de Biblioteca: Buscar en un catálogo de biblioteca para ver si un libro está disponible no reserva el libro ni lo presta. Puedes buscar repetidamente sin afectar la disponibilidad. OPTIONS es como consultar el catálogo - te dice qué es posible sin hacerlo.
Visitar un Museo: Caminar por un museo y ver exhibiciones es seguro. Las exhibiciones no cambian porque las miraste. Puedes visitar el mismo museo muchas veces, y el arte permanece igual. Las peticiones GET funcionan así - estás observando, no modificando.
Ejemplo de Código
# ===== GET - Recuperar Recurso =====
# Método seguro más común
GET /api/products/123 HTTP/1.1
Host: api.example.com
Accept: application/json
# Respuesta
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=3600
ETag: "v1-abc123"
{
"id": 123,
"name": "Widget",
"price": 9.99,
"stock": 100
}
# Puede ser llamado repetidamente sin efectos secundarios
# Navegadores, CDNs, proxies almacenan esto agresivamente
# ===== HEAD - Verificar Metadatos del Recurso =====
# Devuelve solo cabeceras, sin cuerpo
HEAD /api/files/photo.jpg HTTP/1.1
Host: api.example.com
# Respuesta (sin cuerpo)
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 524288
Last-Modified: Tue, 07 Jan 2026 14:30:00 GMT
ETag: "photo-v2-xyz789"
# Caso de uso: Verificar si el archivo fue modificado antes de descargarlo
# Seguro de llamar muchas veces para monitorear actualizaciones
# ===== OPTIONS - Descubrir Métodos Permitidos =====
# Petición preflight CORS
OPTIONS /api/users HTTP/1.1
Host: api.example.com
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
# Respuesta
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
# Seguro - solo descubre qué está permitido, no hace nada
# ===== TRACE - Loopback Diagnóstico =====
# Devuelve petición tal como fue recibida (raramente usado, a menudo deshabilitado)
TRACE /api/debug HTTP/1.1
Host: api.example.com
X-Custom-Header: test-value
# Respuesta (hace eco de la petición)
HTTP/1.1 200 OK
Content-Type: message/http
TRACE /api/debug HTTP/1.1
Host: api.example.com
X-Custom-Header: test-value
# Seguro - solo hace eco de la petición para depuración
// Ejemplos en JavaScript de métodos seguros
// ===== GET - Obtener Datos =====
// Puede ser llamado repetidamente sin efectos secundarios
async function getProduct(id) {
const response = await fetch(`/api/products/${id}`, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (response.ok) {
return await response.json();
}
throw new Error('Producto no encontrado');
}
// Seguro de llamar múltiples veces
const product1 = await getProduct(123);
const product2 = await getProduct(123); // Mismo resultado
const product3 = await getProduct(123); // Mismo resultado
// Los navegadores almacenan en caché respuestas GET automáticamente
fetch('/api/products/123', { method: 'GET' }); // Obtener del servidor
fetch('/api/products/123', { method: 'GET' }); // Puede usar respuesta almacenada
// ===== HEAD - Verificar si Existe Recurso =====
async function fileExists(filename) {
const response = await fetch(`/api/files/${filename}`, {
method: 'HEAD'
});
return response.ok; // True si el archivo existe, false en caso contrario
}
// Seguro de verificar repetidamente
const exists = await fileExists('photo.jpg');
console.log('El archivo existe:', exists);
// Verificar si el archivo fue modificado
async function wasModified(filename, lastModified) {
const response = await fetch(`/api/files/${filename}`, {
method: 'HEAD'
});
const serverLastModified = response.headers.get('Last-Modified');
return serverLastModified !== lastModified;
}
// ===== OPTIONS - Preflight CORS =====
// Los navegadores envían esto automáticamente para peticiones cross-origin
// Típicamente no lo llamas manualmente, pero aquí está cómo:
async function checkCorsSupport(url) {
const response = await fetch(url, {
method: 'OPTIONS',
headers: {
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'Content-Type'
}
});
const allowedMethods = response.headers.get('Access-Control-Allow-Methods');
return allowedMethods.includes('POST');
}
// ===== Comparación SEGURO vs NO SEGURO =====
// Seguro: Puede ser reintentado, almacenado en caché, precargado
async function getSafeData() {
// GET es seguro - sin efectos secundarios
const response = await fetch('/api/stats', { method: 'GET' });
return response.json();
}
// No seguro: Crea efectos secundarios
async function createOrder() {
// POST NO es seguro - crea un nuevo pedido
const response = await fetch('/api/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product_id: 123, quantity: 1 })
});
return response.json();
}
// El método seguro puede ser llamado en paralelo sin coordinación
const [stats1, stats2, stats3] = await Promise.all([
getSafeData(),
getSafeData(),
getSafeData()
]); // Seguro - los tres devuelven mismos datos
// El método no seguro NO debería ser llamado en paralelo (¡crea 3 pedidos!)
// NO HAGAS ESTO:
const badIdea = await Promise.all([
createOrder(),
createOrder(),
createOrder()
]); // Crea 3 pedidos separados - ¡NO seguro!
Diagrama
graph TB
subgraph "Métodos Seguros (Solo Lectura)"
GET[GET
Recuperar recurso]
HEAD[HEAD
Obtener solo metadatos]
OPTIONS[OPTIONS
Descubrir capacidades]
TRACE[TRACE
Loopback diagnóstico]
end
subgraph "Propiedades de Métodos Seguros"
P1[Sin efectos secundarios]
P2[Repetible]
P3[Almacenable en caché]
P4[Precargable]
P5[Amigable con rastreadores]
end
GET --> P1
GET --> P2
GET --> P3
GET --> P4
GET --> P5
HEAD --> P1
HEAD --> P2
HEAD --> P3
OPTIONS --> P1
OPTIONS --> P2
TRACE --> P1
TRACE --> P2
subgraph "Casos de Uso Comunes"
U1[Carga de página del navegador
Múltiples peticiones GET]
U2[Caché de CDN
Almacenar respuestas GET]
U3[Monitoreo de archivos
HEAD para verificar actualizaciones]
U4[Preflight CORS
OPTIONS antes de POST]
U5[Rastreo de motores de búsqueda
GET todos los enlaces]
end
GET -.-> U1
GET -.-> U2
GET -.-> U5
HEAD -.-> U3
OPTIONS -.-> U4
style GET fill:#90EE90
style HEAD fill:#90EE90
style OPTIONS fill:#90EE90
style TRACE fill:#90EE90
Notas de Seguridad
Requisitos Principales:
- Nunca implementar efectos secundarios en métodos seguros - hacerlo viola la semántica HTTP y puede causar vulnerabilidades de seguridad.
- Las peticiones GET nunca deberían eliminar datos, enviar emails, transferir dinero o modificar estado.
- Los atacantes pueden explotar endpoints GET no seguros a través de CSRF (Cross-Site Request Forgery) embebiendo URLs maliciosas en emails o sitios web.
- Implementar autenticación y autorización apropiadas incluso para métodos seguros para prevenir divulgación de información.
- Usar limitación de tasa en endpoints GET para prevenir ataques de enumeración y scraping de datos.
Mejores Prácticas:
- No incluir datos sensibles en URLs usadas por peticiones GET ya que las URLs se registran en historial del navegador, logs del servidor y logs de proxy.
- Implementar cabeceras de caché apropiadas para prevenir que datos sensibles sean almacenados por intermediarios.
- Para APIs que exponen datos sensibles usar POST en lugar de GET para evitar logging de URL, o cifrar parámetros de consulta.
- Nunca confiar en datos proporcionados por el usuario en query strings - validar y sanitizar todas las entradas.
- Monitorear patrones anormales de peticiones GET que puedan indicar reconocimiento o exfiltración de datos.
- Implementar logging apropiado y rastros de auditoría para acceso a recursos sensibles incluso vía métodos seguros..
Mejores Prácticas
- Nunca modificar estado en peticiones GET: Seguir estrictamente la semántica HTTP - GET es solo lectura
- Usar cabeceras de caché apropiadas: Configurar
Cache-Control,ETag,Last-Modifiedpara respuestas GET - Soportar HEAD para todos los endpoints GET: Devolver mismas cabeceras que GET pero sin cuerpo
- Implementar OPTIONS para CORS: Soportar peticiones preflight apropiadamente
- Hacer respuestas GET determinísticas: Misma petición debería devolver mismos datos (hasta que el estado cambie externamente)
- Usar parámetros de consulta para filtrado:
/api/products?category=electronics&sort=price - Devolver 304 Not Modified: Cuando el cliente envía
If-None-MatchoIf-Modified-Sincey el recurso no ha cambiado - Documentar parámetros de consulta: Especificar claramente filtros soportados, ordenamiento, paginación
- Implementar paginación para colecciones: Prevenir devolver conjuntos de datos enormes en una sola respuesta GET
- Usar códigos de estado apropiados: 200 para éxito, 404 para no encontrado, 304 para no modificado
Errores Comunes
Usar GET para eliminar o modificar: Endpoints como /api/delete-user?id=123 violan la semántica HTTP y son vulnerables a CSRF.
Incluir datos sensibles en URLs: GET /api/reset-password?token=secret123 expone tokens en logs e historial del navegador.
No almacenar en caché respuestas GET: Faltan cabeceras Cache-Control desperdicia ancho de banda y recursos del servidor.
Ignorar peticiones HEAD: No soportar HEAD para endpoints que soportan GET.
Efectos secundarios en GET: Incrementar contadores de vistas, registrar analíticas o enviar notificaciones en peticiones GET.
No implementar 304 Not Modified: Siempre devolver respuesta completa incluso cuando el cliente tiene versión almacenada.
Tratar OPTIONS como no seguro: Algunos frameworks bloquean OPTIONS o requieren autenticación, rompiendo preflight CORS.
Devolver datos diferentes para mismo GET: Respuestas no determinísticas confunden cachés y clientes.
Sin paginación en colecciones: GET /api/products devolviendo todos los 10,000 productos en lugar de resultados paginados.
Usar GET para operaciones sensibles: Enlaces de reseteo de contraseña que desencadenan acción en GET en lugar de requerir confirmación POST.