Cómo una tarjeta de aprobación de API muestra el destino real
Crea una tarjeta de aprobación de API que muestre el destino HTTP real mediante la canonicalización del esquema, host, puerto, método, ruta y URL codificadas.

Un revisor no puede aprobar una acción HTTP a partir de una cadena que solo se parece a un destino. La tarjeta debe mostrar el destino de solicitud que el transporte utilizará realmente, después del análisis y antes de que las credenciales salgan del equipo.
Parece obvio hasta que un agente envía HTTPS://API.EXAMPLE.TEST:443/%76%31/../admin, un cliente lo acepta y la persona ve una etiqueta abreviada como api.example.test. Una tarjeta así no solicita un consentimiento informado. Pide al usuario que confíe en un elemento visual que puede no coincidir con la pila HTTP.
La solución no consiste en enseñar a los revisores todos los detalles de la sintaxis de las URL. Consiste en crear una única descripción canónica de la solicitud, mostrarla con claridad y garantizar que el ejecutor use esa misma descripción. El esquema, el host, el puerto efectivo, el método y la ruta son el mínimo. Los valores de consulta, las redirecciones, los encabezados controlados por el solicitante y la identidad del cuerpo suelen tener que aparecer junto a ellos, porque pueden cambiar la acción de forma igual de drástica.
Cómo consigue un sí una tarjeta de aprobación
Una tarjeta de aprobación consigue un sí solo cuando nombra la acción de red en términos que el revisor pueda comprobar. Un nombre de host por sí solo es una afirmación de identidad, no una descripción de la solicitud. POST https://billing.example.test/v1/invoices/481/refund dice mucho más que billing API o example.test.
Coloca primero la línea de acción, en un orden fijo:
POST https://billing.example.test/v1/invoices/481/refund
Después, coloca justo debajo los detalles que cambian el significado:
Authorization: injected from vault entry "billing-production"
Query: dry_run=false
Body: JSON, 214 bytes, sha256: 7b1f...c0a9
No pongas el valor de la credencial, un marcador de autorización ni el nombre amistoso de una integración en el lugar que corresponde al destino. Esas etiquetas pueden ayudar al revisor a reconocer el contexto, pero no prueban cuál es el destino.
El método debe aparecer en la primera línea porque cambia las consecuencias de una misma ruta. GET /exports/481 y DELETE /exports/481 no son variantes de una misma acción. Son acciones distintas y nunca deben quedar reducidas a una sola etiqueta de aprobación.
La ruta debe aparecer en la primera línea porque normalmente ahí se encuentra el enrutamiento de la API. Una tarjeta que muestra api.example.test obliga al revisor a deducir si el agente está leyendo un perfil, creando un token de acceso o eliminando un proyecto. Es una mala forma de usar una interrupción de aprobación.
La canonicalización es un contrato de presentación, no una coincidencia de permisos
La canonicalización responde a «¿Qué debe ver una persona para esta solicitud analizada?». No responde a «¿Qué destinos están permitidos?». Los equipos suelen mezclar ambas tareas y terminan creando una lista de permitidos frágil disfrazada de formato sencillo.
Para una tarjeta de aprobación, crea un registro estructurado del destino después de analizarlo:
{
"method": "POST",
"scheme": "https",
"host": "api.example.test",
"port": 443,
"port_display": null,
"path": "/v1/invoices/481/refund",
"query": "dry_run=false",
"raw_url": "HTTPS://API.EXAMPLE.TEST:443/v1/invoices/481/refund?dry_run=false"
}
El ejecutor debe tomar esos mismos campos estructurados, o una URL serializada a partir de ellos. No analices una vez para la tarjeta y pases después la cadena original a otra biblioteca. Esa separación es lo que convierte una pantalla de revisión en puro teatro.
RFC 3986 distingue varias categorías de normalización seguras. Trata el esquema y el host como elementos que no distinguen mayúsculas de minúsculas, recomienda usar dígitos hexadecimales en mayúscula en los escapes porcentuales y describe la eliminación de segmentos de punto. También advierte que el código debe analizar los componentes de la URI antes de decodificar los octetos con escapes porcentuales, porque decodificar en el momento equivocado puede convertir los datos en delimitadores. Es un consejo práctico de ingeniería, no un detalle meramente teórico de una especificación.
Conserva un segundo registro para la entrada sin procesar del agente. Debe estar en el registro de actividad y en una vista de detalles para cuando alguien necesite investigar una solicitud extraña. No debe competir con la línea de acción canónica por la atención del revisor.
Una regla útil es sencilla: la tarjeta muestra una descripción normalizada, el diario conserva tanto la descripción como la entrada y las decisiones de autorización no usan ninguna de las dos como sustituto de reglas de alcance explícitas. Son productos de datos distintos.
Analiza primero y rechaza lo que el transporte no pueda explicar
Un analizador de URL forma parte del límite de seguridad una vez que una persona aprueba su resultado. Elige un comportamiento de análisis para los esquemas de URL compatibles y conviértelo en la fuente de verdad tanto para la presentación como para la ejecución.
Para las API HTTP normales, rechaza las entradas que dejan dudas en lugar de intentar ser útil. Las referencias relativas necesitan una URL base explícita antes de tener un host. Los fragmentos no forman parte de una solicitud HTTP y no deben aparecer como si influyeran en el servidor. La información de usuario, como https://[email protected]/, casi siempre induce a error en un flujo de aprobación de API y debe rechazarse, no ocultarse en silencio.
Usa un flujo de análisis con un punto de fallo claro:
- Acepta solo una URL absoluta
httpohttpspara el canal de API saliente. - Analízala con la implementación de URL elegida por el ejecutor de la acción.
- Rechaza la información de usuario, la ausencia de host, los valores de puerto mal formados, los esquemas no compatibles y los escapes porcentuales no válidos.
- Construye la solicitud real a partir de los componentes analizados y los encabezados aprobados.
- Muestra la tarjeta a partir de esos componentes y envía después esa solicitud exacta.
No intentes hacerlo con separaciones de cadenas escritas a mano. El primer @, :, /, ? y # no significan lo mismo en todas las posiciones. Las autoridades IPv6 necesitan corchetes. Un signo de dos puntos después de un corchete puede introducir un puerto, mientras que los dos puntos dentro de los corchetes forman parte de la dirección. Un analizador conoce esa diferencia; una expresión regular corta normalmente no.
El estándar WHATWG URL define el comportamiento de análisis y serialización de URL, hosts, dominios y direcciones IP. Sus indicaciones de seguridad también señalan la confusión que el texto bidireccional puede crear entre un host y una ruta, y recomiendan mostrar solo el host en esa situación. Un producto de seguridad debe extraer una lección más estricta: mantén la autoridad separada visualmente de la ruta en todas las tarjetas, no solo cuando aparezcan cadenas poco habituales.
Si la capa de acciones tiene un cliente personalizado, demuestra que coincide con el analizador usando un corpus de pruebas. No des por hecho que dos bibliotecas maduras toleran exactamente igual los espacios, las barras invertidas, los nombres de host Unicode o las formas numéricas de IP poco habituales. La coincidencia es una propiedad que se prueba.
Decodifica los escapes porcentuales sin cambiar la ruta
La codificación porcentual crea el tipo más peligroso de URL engañosa: una que parece inofensiva después de una decodificación superficial, pero que significa algo distinto para el enrutador, el proxy o el servicio ascendente.
Considera estas rutas:
/v1/projects/%2E%2E/admin
/v1/projects/%252E%252E/admin
/v1/files/report%2Ffinal
La primera contiene puntos codificados porcentualmente. La segunda contiene un signo de porcentaje codificado seguido de 2E, que no es la misma entrada. La tercera contiene una barra codificada dentro de un segmento de ruta. Si una capa de presentación decodifica las tres repetidamente hasta obtener signos de puntuación legibles, puede mostrar una estructura de ruta que el cliente no envió.
RFC 3986 ofrece un caso seguro limitado: los escapes porcentuales de caracteres no reservados pueden decodificarse durante la normalización. Los caracteres no reservados son letras, dígitos, guion, punto, guion bajo y tilde. Los caracteres reservados como /, ?, #, @ y : deben permanecer codificados cuando su decodificación cambie los límites de los componentes o los delimitadores. La RFC también indica que una implementación no debe codificar ni decodificar la misma cadena más de una vez.
De ahí sale una buena regla de presentación:
Raw path: /v1/%75sers/alice%7Eops/report%2Ffinal
Card path: /v1/users/alice~ops/report%2Ffinal
Wire path: /v1/users/alice~ops/report%2Ffinal
La tarjeta hace legibles %75 y %7E porque representan caracteres no reservados. Mantiene visible %2F porque una barra cambiaría la estructura de segmentos de la ruta. La forma de la tarjeta y la forma enviada pueden diferir de manera inofensiva, pero deben conservar el mismo significado de enrutamiento.
No elimines los segmentos de punto después de decodificar la ruta de forma indiscriminada. Analiza la ruta según su estructura codificada, aplica un procedimiento de normalización definido y conserva los escapes que transporten caracteres reservados como datos. Si el servicio descendente aplica un orden de decodificación distinto, es un problema de compatibilidad y seguridad que conviene exponer en las pruebas, no una razón para que la tarjeta adivine.
Un nombre de host no es toda la autoridad
La autoridad de un destino HTTP incluye el host y, cuando no es el predeterminado, el puerto. Omitir el puerto hace que una tarjeta de revisión mienta por omisión.
Trata estos casos como distintos:
https://api.example.test/v1/keys
https://api.example.test:8443/v1/keys
http://api.example.test/v1/keys
El primero normalmente usa el puerto 443. El segundo usa el puerto 8443. El tercero usa un esquema distinto y normalmente el puerto 80. Un revisor puede aceptar una llamada a una API de producción mediante HTTPS y rechazar una solicitud a un servicio de pruebas en un puerto personalizado. La tarjeta debe permitirle tomar esa decisión.
Normaliza el esquema y el nombre de host a minúsculas. Omite el puerto solo cuando sea el predeterminado para el esquema analizado: 80 para http y 443 para https. No omitas un puerto porque un registro DNS conduzca casualmente a un lugar conocido.
Los nombres de dominio internacionalizados requieren el mismo cuidado. Una forma Unicode fácil de leer puede resultar más clara para una persona, mientras que la forma que usa DNS en el cable emplea etiquetas ASCII. Si muestras Unicode, muestra también la forma ASCII en los detalles y usa un analizador que aplique un algoritmo definido para procesar hosts. No inventes tu propia conversión a punycode ni compares cadenas de presentación para decidir si son equivalentes.
Los literales IP merecen un tratamiento propio. Muestra corchetes alrededor de las direcciones IPv6, conserva los puertos no predeterminados y etiqueta una dirección literal como literal IP. Una solicitud a https://[2001:db8::9]/v1/keys no debe parecer un servicio de producción identificado por nombre solo porque el agente haya incluido un alias agradable en un campo de notas.
Los alias plantean un problema distinto. api.internal, api y 10.0.0.9 pueden terminar hoy en el mismo servidor y divergir después de un cambio DNS. No reescribas uno silenciosamente como otro para la aprobación. Muestra la autoridad analizada que solicitó el cliente. Si el sistema resuelve DNS antes de abrir una conexión, muestra la dirección seleccionada como contexto de conexión y regístrala en la pista de auditoría. La autoridad sigue siendo aquello que nombra la solicitud HTTP.
HTTP hace explícita esa distinción. RFC 9110 indica que el campo Host proporciona la información de host y puerto de la URI de destino, mientras que HTTP/2 y HTTP/3 pueden transportar esa información en :authority. RFC 9113 indica que un intermediario que genere Host a partir de la autoridad de HTTP/2 debe usar :authority, salvo que cambie el destino de la solicitud. Por tanto, una tarjeta debe tratar un campo de autoridad proporcionado por el solicitante como material de enrutamiento, no como metadatos decorativos.
El método y la ruta necesitan un peso visual propio
Coloca juntos el método HTTP, la autoridad y la ruta porque los revisores leen la acción como una frase. Después, da al método y a los segmentos de ruta peligrosos suficiente contraste para que una mirada rápida no los reduzca a una URL larga.
Esta disposición funciona porque mantiene las partes en un orden estable:
DELETE
https://api.example.test/v1/projects/acme/production
Para una solicitud que modifica un objeto, incluye su identificador en la ruta visible. Recortar el final de /v1/projects/acme/production para que quepa en una tarjeta es contraproducente. Si falta espacio, recorta primero los valores de consulta largos o las vistas previas del cuerpo, nunca el segmento final de la ruta que identifica el destino.
Las mayúsculas y minúsculas deben conservarse en la ruta. RFC 3986 indica que la sintaxis URI genérica trata los componentes distintos del esquema y el host como sensibles a mayúsculas y minúsculas, salvo que el esquema indique lo contrario. Muchos frameworks enrutan teniendo en cuenta las mayúsculas incluso cuando una API concreta no lo hace. Convertir /Admin/DeleteUser en /admin/deleteuser crea una afirmación sobre una solicitud que nunca se hizo.
Una ruta de solicitud también puede parecer inofensiva mientras la consulta cambia el efecto:
POST https://api.example.test/v1/invoices/481/refund?dry_run=false
POST https://api.example.test/v1/invoices/481/refund?dry_run=true
Muestra un resumen breve de la consulta debajo de la línea de acción cuando los parámetros cambien el alcance, el comportamiento o la identidad. Para consultas no estructuradas o muy largas, muestra la consulta codificada completa en un área de detalles desplegable y un resumen decodificado y redactado en la tarjeta principal. Nunca decodifiques un token hasta convertirlo en un secreto legible solo porque la tarjeta quiera resultar más amable.
El cuerpo de la solicitud puede importar incluso más que la ruta. Una aprobación para PATCH /v1/users/alice dice poco si el cuerpo puede conceder un rol de administrador. Muestra como mínimo el tipo de contenido, la longitud en bytes y un resumen estable. Para formatos estructurados como JSON, una pequeña vista previa de los campos modificados puede ayudar, siempre que la vista previa proceda de los mismos bytes que se enviarán. Volver a serializar un objeto para mostrarlo después de firmar o calcular un hash sobre otra secuencia de bytes crea el mismo problema de divergencia que volver a analizar las URL.
Los encabezados y las redirecciones pueden cambiar el destino
Una URL canónica no salva un flujo de aprobación si otro campo de la solicitud puede dirigir la conexión. La tarjeta debe restringir esos campos o mostrar sus efectos.
Empieza por Host y :authority. Un cliente HTTP normalmente los deriva de la URL de destino. Si una interfaz de acciones permite al solicitante sobrescribirlos, rechaza la sobrescritura salvo que el transporte tenga una razón documentada para admitirla. Si la admites, la línea de aprobación debe mostrar tanto el destino de conexión como la autoridad solicitada, de forma que una persona pueda compararlos.
La configuración del proxy merece el mismo tratamiento. Un proxy cambia el interlocutor inmediato, pero no necesariamente el destino de origen. No sustituyas el origen por la dirección del proxy en la tarjeta. Muestra el origen como la acción que se aprueba y el proxy como contexto de transporte. Si el proxy puede reescribir campos de destino, trátalo como un componente del ejecutor con pruebas, registros y una decisión de confianza independiente.
Las redirecciones son acciones nuevas cuando cambia su destino. Un POST puede convertirse en un GET según el comportamiento de la redirección, o reenviarse a una nueva autoridad. La aprobación original debe cubrir solo el destino original. Antes de seguir una redirección, analiza el valor de Location, construye la siguiente solicitud propuesta, compara su esquema, autoridad, método, ruta, consulta y comportamiento del cuerpo, y vuelve a preguntar si cambia algo relevante.
Evita el atajo popular de aprobar un «sitio» durante toda una ejecución y tratar como inofensiva cualquier redirección dentro de él. Resulta menos molesto, pero convierte el análisis de URL y la política de redirecciones en una ampliación invisible de privilegios. Si la ejecución necesita permisos amplios, expresa ese alcance de forma explícita en el texto de aprobación en lugar de dejar que las redirecciones lo introduzcan a escondidas.
Pon la entrada sin procesar en el registro, no en la línea de decisión
Un registro de auditoría debe contener suficientes detalles para responder a dos preguntas distintas: qué solicitó el agente y qué intentó ejecutar el sistema. Una sola cadena URL no siempre puede responder a ambas.
Registra exactamente la cadena URL original recibida, sujeta a las reglas de redacción de secretos. Registra por separado el destino canónico. Añade la autoridad de conexión final y la dirección resuelta si el ejecutor realizó la resolución. Para HTTP/2 o HTTP/3, registra la :authority efectiva; para HTTP/1.1, registra el valor efectivo de Host. Registra los saltos de redirección como solicitudes intentadas individuales, no como una nota al pie de la primera llamada.
Una entrada del diario puede tener esta forma:
{
"request_id": "req_01J...",
"agent_input_url": "HTTPS://API.EXAMPLE.TEST:443/v1/%75sers/alice%7Eops",
"approved_target": "GET https://api.example.test/v1/users/alice~ops",
"effective_authority": "api.example.test",
"effective_port": 443,
"connection_ip": "203.0.113.42",
"result": "200"
}
El ejemplo usa un rango de direcciones reservado para documentación como IP de conexión. En un registro real, protege los secretos de las consultas, el material de autorización y los cuerpos sensibles antes de que los datos lleguen a un registro de larga duración. Un resumen ayuda a relacionar el contenido aprobado con el contenido ejecutado sin copiar cargas privadas en todas las pantallas.
La distinción entre la entrada original y el destino canónico resulta muy útil durante una investigación. Si una tarjeta mostraba una ruta normal, pero la entrada original contenía varias capas de codificación, puedes determinar si no coincidieron el analizador, el elemento visual o el cliente HTTP. Si solo guardaste una URL bonita, eliminaste las pruebas necesarias para encontrar el defecto.
Los diarios Activity y Sessions de Sallyport se proyectan a partir de un único registro de auditoría cifrado y encadenado mediante hashes, así que la representación del destino debe escribirse una vez como parte del registro de la acción, en lugar de reconstruirse después a partir de cadenas de la interfaz. Su comprobación sin conexión sp audit verify solo es útil si los campos registrados de la acción eran honestos en el momento de la ejecución.
Prueba las discrepancias que las URL normales nunca revelan
Las pruebas unitarias importantes no son diez ejemplos normales de https://api.example.test/v1/users. Son los casos en que una cadena original, un elemento de presentación y una biblioteca de transporte podrían no coincidir.
Crea un corpus basado en tablas que compruebe los campos analizados, el destino visible, el destino enviado y la decisión. Incluye como mínimo estas familias:
- cambios de mayúsculas y minúsculas en el esquema y el host, con puertos predeterminados y no predeterminados;
- segmentos de punto y escapes porcentuales tanto de caracteres no reservados como reservados;
- signos de porcentaje y barras codificados, además de secuencias de escape mal formadas;
- literales IPv6, entradas de host Unicode e información de usuario que deba rechazarse;
- valores de consulta que cambien el comportamiento de la acción, además de destinos de redirección en otra autoridad.
Un caso de prueba debe hacer explícita la representación esperada:
{
"input": "HTTPS://API.EXAMPLE.TEST:443/v1/%75sers/alice%7Eops?role=viewer",
"decision": "approve",
"card": "GET https://api.example.test/v1/users/alice~ops?role=viewer",
"wire_url": "https://api.example.test/v1/users/alice~ops?role=viewer"
}
Después añade casos negativos que deban fallar antes de la aprobación:
{
"input": "https://[email protected]/v1/users",
"decision": "reject",
"reason": "userinfo is not supported for outbound API actions"
}
Ejecuta el corpus con el código exacto del cliente que abre la conexión. Una suite de pruebas limitada al analizador detecta errores de presentación, pero no comportamientos del transporte como que una biblioteca normalice una ruta vacía, inyecte una autoridad predeterminada o aplique sus propias reglas de redirección.
Por último, prueba la interfaz tal como la utiliza un revisor. Confirma que el método completo, el host, el puerto cuando esté presente y el segmento final de la ruta sigan visibles en tamaños de ventana normales. El texto de seguridad falla cuando la persona tiene que pasar el cursor, expandir o desplazarse para descubrir que una solicitud elimina datos de producción. La tarjeta debe hacer visible la diferencia importante antes de que el botón de aprobación reciba el foco.
Una aprobación humana puede ser un control sólido, pero solo será tan sólida como la descripción de la solicitud que se ponga delante de la persona. Construye esa descripción a partir de componentes analizados, ejecuta esos componentes, conserva la entrada original para examinarla después y rechaza la ambigüedad en lugar de decorarla.
FAQ
¿Qué URL debe mostrar una solicitud de aprobación de API?
Una tarjeta de aprobación debe mostrar el destino analizado que utilizará el cliente HTTP: esquema, nombre de host, puerto efectivo, método, ruta y cualquier valor de consulta que cambie la acción. Conserva la cadena enviada como prueba, pero no la conviertas en el elemento principal que el revisor tenga que interpretar.
¿Debe una tarjeta de aprobación decodificar las URL con escapes porcentuales?
Decodifica los escapes porcentuales solo después de analizar la URL por componentes y únicamente cuando la decodificación no pueda convertir los datos en sintaxis. RFC 3986 permite a los normalizadores decodificar escapes de caracteres no reservados, pero decodificar %2F en / cambia un segmento de ruta por un separador.
¿Deben ocultarse los puertos predeterminados en las solicitudes de aprobación de API?
Por lo general, sí. https://api.example.test:443/payments y https://api.example.test/payments llegan al mismo puerto HTTPS predeterminado, así que mostrarlos como destinos distintos da a los atacantes margen para crear ruido visual. Conserva los puertos no predeterminados porque cambian la autoridad a la que se conecta el cliente.
¿Distinguen las tarjetas de aprobación las mayúsculas y minúsculas de las rutas URL?
No. Convierte el nombre de host a minúsculas para compararlo y mostrarlo, pero trata las mayúsculas y minúsculas de la ruta como significativas, salvo que las reglas del propio destino indiquen lo contrario. Muchos servidores enrutan /Admin y /admin de forma distinta.
¿Deben aparecer los parámetros de consulta en una solicitud de aprobación de API?
Sí, cuando afecta a la acción. Una operación destructiva oculta detrás de una cadena de consulta aparentemente inofensiva sigue siendo destructiva, así que muestra la consulta o un resumen claro de sus parámetros decodificados. Redacta secretos como tokens firmados en lugar de omitir toda la consulta.
¿Puede una tarjeta de aprobación tratar los alias de host como el mismo destino?
No. Una dirección IP, un nombre de host local, un dominio Unicode y un nombre DNS público pueden plantear riesgos distintos aunque parezcan relacionados. Registra los alias y las direcciones resueltas como contexto adicional, pero aprueba la autoridad literal analizada, salvo que la capa de transporte la reescriba deliberadamente.
¿Las redirecciones HTTP requieren otra aprobación?
Una redirección es un nuevo destino de solicitud y requiere una decisión nueva cuando cambian el esquema, el host, el puerto, el método o una parte significativa de la ruta. Aprobar la primera URL no da permiso al cliente para seguir un salto posterior hacia otra autoridad.
¿Cuál es el orden seguro para analizar y aprobar una URL saliente?
El orden seguro es analizar, validar el esquema y la estructura de la URL, construir la solicitud real y después mostrar el destino a partir de esos valores estructurados. Mostrar primero la entrada sin procesar facilita que la tarjeta y la biblioteca de transporte no coincidan.
¿Deben los registros de auditoría guardar la URL original o la canónica?
Guarda ambas, pero asígnales funciones distintas. La cadena sin procesar ayuda al investigador a reproducir lo que proporcionó el agente, mientras que el destino canónico indica a qué intentó conectarse el cliente.
¿Puede un encabezado Host personalizado inducir a error a una pantalla de aprobación de API?
Una solicitud puede llevar una URL de aspecto válido mientras un encabezado Host proporcionado por el solicitante, una configuración de proxy, una regla de redirección o un transporte personalizado la envía a otro lugar. Construye la autoridad final en un único punto y rechaza los campos de enrutamiento contradictorios o muéstralos de forma destacada como parte del destino.