Empieza por una comprobación que cabe en una pestaña. Abre Red (Network) y compara la barra de direcciones completa con la línea de petición del documento. La barra puede mostrar una clave detrás de #. Esa misma cadena no debería aparecer en la línea de petición. Si aparece, no es el comportamiento por defecto del navegador: la página escribió el fragmento en una consulta, o un script lo leyó y lo metió en una petición.
La consulta y la almohadilla no son la misma capa
Los enlaces de cifrado de un solo uso suelen resumirse así: «la clave está en la URL». La frase es demasiado gruesa. Mezcla dos hechos distintos. Una URL puede llevar consulta y fragmento a la vez: ? abre la consulta, # abre el fragmento. Ambos se ven en la barra de direcciones y, al copiar, la gente se lleva la cadena entera. HTTP no los trata igual.
La consulta forma parte del destino de la petición. Abres s.html?id=abc123 y el servidor, el proxy inverso, la CDN y el registro de acceso están diseñados para ver id=abc123. El fragmento no entra en esa petición del documento. Abres s.html?id=abc123#la-clave y el navegador pide al servidor la página con el id. Lo que va detrás de la almohadilla se queda en esta pestaña para que los scripts lo lean con location.hash.
Así que «la clave está en la URL» solo responde si una persona puede ver la cadena. No responde si el servidor puede ver la clave. Lo que encaja para una clave es el fragmento detrás de la almohadilla, siempre que la implementación lo deje ahí y no lo meta en la consulta por comodidad.
Qué dicen las normas: el fragmento se queda en el cliente
No es un convenio privado de un producto. La sección 3.5 de RFC 3986 define el fragmento como identificador de un «recurso secundario»: aparece la almohadilla y sigue hasta el final del URI. Cómo se interpreta depende del tipo de documento recuperado. Lo resuelve el cliente. El esquema del URI no lo reescribe.
La sección 7.1 de RFC 9110 aplica la misma regla a HTTP: el URI de destino que deriva el navegador no incluye fragmento, porque el identificador de fragmento es para el cliente. Al pedir el documento, la línea de petición no debería contener la almohadilla ni lo que viene después.
Referer corta por el mismo sitio. RFC 9110 dice que un agente de usuario que genera Referer no debe incluir fragmento ni userinfo. La página de Referer en MDN coincide: la cabecera puede llevar origen, ruta y consulta, no un fragmento #. La Referrer Policy del W3C, al convertir una URL en referrer, vacía primero el fragmento y luego decide si deja ruta y consulta.
Esos tres documentos demuestran una sola cosa: un navegador conforme a la norma no escribirá la clave detrás de la almohadilla en la línea de petición HTTP ni en Referer. No demuestran que los scripts de la página, una extensión o el texto que pegas en otro sitio también la borren.
Si la clave va en la consulta, el log la ve en claro
Escribir la clave como ?id=abc123&key=... es más fácil de publicar. El servidor puede pedir el cifrado y descifrarlo con la misma consulta. Es habitual en páginas de «cifrar en línea» que quieren resolverlo todo en una petición. Es lo contrario de «el anfitrión no debería ver la clave».
La consulta aparece en la línea de petición. También entra en la mayoría de registros de acceso, logs de proxy inverso y algunos informes de CDN. En cuanto la clave está en la consulta, «solo guardamos cifrado» ya es falso en la capa de logs. Quien abra el access log de ese día tiene la segunda mitad necesaria para descifrar.
Alguien propondrá mover la clave a un cuerpo POST. Eso puede sacarla de los logs de URL. La clave sigue saliendo del navegador y llega a la máquina que llamaste «conocimiento cero». El valor del fragmento es el inverso: la clave no tiene que salir como campo HTTP. La página lee location.hash en esta pestaña.
| Dónde la pones | ¿La ve una persona? | ¿La ve esta petición HTTP? |
|---|---|---|
Consulta después de ? |
Sí, en la barra y en el texto copiado | Sí. Línea de petición, proxies y registros la anotan |
Fragmento después de # |
Sí, en la barra y en el texto copiado | Por defecto, no. Línea de petición y Referer la omiten según la norma |
| Campo POST | No en la barra de direcciones | Sí. El cuerpo llega al servidor |
| Solo en memoria, nunca en una URL | La otra persona no la ve, salvo otro canal | No. Un enlace de un toque tampoco puede entregar la clave |
La separación que funciona: localizador en la consulta, clave en la almohadilla
Un enlace de cifrado de un solo uso tiene que hacer dos trabajos a la vez: decirle al servidor qué cifrado pedir, y decirle al navegador del destinatario qué clave usar en local. Esos trabajos no deberían compartir un mismo campo HTTP.
La separación comprobable es s.html?id={id}#{key}. La consulta lleva solo el id de localización. La almohadilla lleva solo la clave. Al crear, el navegador ejecuta AES-256-GCM con Web Crypto y, de salida, solo puede ir cifrado. Al leer, el script lee location.hash, pide el cifrado al servidor y descifra en esta pestaña. El servidor, por diseño, guarda el cifrado un tiempo y lo destruye al leerlo.
El enlace de un solo uso de MakePwd sigue ese límite. La página de creación y la de lectura se abren sin cuenta. La de lectura es pública para el destinatario y no pide iniciar sesión. Sigue siendo una decisión de implementación, no «una almohadilla es un protocolo de cifrado». El fragmento, por sí solo, no mantiene un secreto confidencial. Solo evita que la clave salga de la pestaña como campo HTTP.
No pruebes con una contraseña real, un documento de identidad ni una hoja sin enmascarar. Usa una frase desechable y un enlace de un solo uso generado para esta comprobación. Estás comparando una línea de petición con la barra de direcciones, no volviendo a difundir un secreto.
Compruébalo en Network frente a la barra de direcciones
La nota anterior cubría cómo usar un canario para ver si el texto en claro salió de este dispositivo como dato de negocio. Esta acota la pregunta: ¿la clave entró en HTTP? Puedes terminar los pasos por su cuenta. No hace falta haber leído el otro artículo primero.
Crea un texto de prueba inofensivo y copia el enlace generado completo. Localiza la almohadilla: delante va s.html?id=..., detrás va la clave. Abre una pestaña limpia, abre las herramientas de desarrollo, activa Preserve log y pega el enlace.
- Compara la barra de direcciones con la línea de petición del documento. La barra debería conservar
#y lo que sigue. La URL del documento solo debería mostrar ruta y?id=, no la clave detrás de la almohadilla. - Luego revisa las llamadas XHR / Fetch posteriores. La API de cifrado puede llevar
idpor diseño. La misma clave no debería reaparecer en un cuerpo ni en una consulta. El cuerpo de creación debería ser cifrado, no la frase de prueba que acabas de escribir. - Abre aparte consultas y cuerpos de analytics. Puede aparecer la ruta de la página. Si un script escribe el
location.hrefcompleto, la clave pasa de «el comportamiento HTTP por defecto la ocultó» a «la página la reportó». Eso es un fallo de implementación, no un fallo de la norma.
Tres pases limpios sostienen una afirmación estrecha: en este navegador, en esta apertura, la clave no salió de la pestaña como campo HTTP observado. Cambias de navegador, de versión o de script, y hay que repetirla.
Cuándo falla esta capa de protección
Un fragmento bloquea «esta petición HTTP entregó la clave al anfitrión». En los casos de abajo, la clave nunca dependía del comportamiento HTTP por defecto. La norma no puede ayudar.
Primero, el enlace completo se pega en un chat, un correo o un ticket. La otra parte ve la cadena entera a simple vista, y lo que va detrás de la almohadilla queda en el historial de ese sistema. Algunos clientes tiran el hash y solo previsualizan lo anterior: entonces el destinatario abre una página sin clave, y la lectura debería decírselo en vez de pedirle otra clave al servidor. En ambos casos ya entregaste una credencial al portador a otro sistema.
Segundo, los scripts de la página y las extensiones pueden leer location.hash. Por eso funciona una página de lectura. Por eso un XSS o una extensión hostil pueden llevarse la clave. La sección 17.11 de RFC 9110 ya lo apunta: los fragmentos no entran en la petición, pero siguen visibles para el agente de usuario, las extensiones y los scripts que llegaron con la respuesta. Si una redirección hereda el fragmento de la URL original, también puede llevar el fragmento de este sitio a otro origen.
Tercero, el historial del navegador, compartir pantalla y el portapapeles. La cadena completa de la barra acaba en el historial local. Proyectas la pestaña en una sala de reuniones y lo que va detrás de la almohadilla está en la pared. Nada de eso pasa por tu servidor, y «los fragmentos no se envían por HTTP» no lo rebate.
Cuarto, páginas intermedias o acortadores que reescriben la URL. Si la página del medio solo reenvía ruta y consulta, el hash ya no está cuando el destinatario abre. Si primero lee el href completo con JavaScript y luego salta, la clave entró en el front de ese tercero. Los acortadores, sobre todo, piden una comprobación en vivo: ¿la cadena que entregas sigue siendo la original con #?
Tres afirmaciones que invierten el relato
«La almohadilla es más segura, así que la cadena entera se puede reenviar sin cuidado.» No. Más seguro frente al servidor no es más seguro frente al historial de un chat de grupo. La URL completa es una credencial. Quien la tenga puede abrir la lectura y descifrar.
«Referer podría filtrar la clave a un enlace de salida.» Con las normas vigentes, un navegador que genera Referer debe quitar el fragmento. Lo que sí hay que vigilar es que la página escriba location.href en analytics, logs o un script de terceros. La comprobación sigue siendo el contenido de Network, no la suposición de que «cualquier enlace de salida filtra la clave».
«La página de lectura debería pedir inicio de sesión, o cualquiera puede abrirla.» Eso mezcla «quién tiene el enlace completo» con «quién tiene una cuenta». El control de acceso de un enlace de cifrado de un solo uso es la cadena misma. Poner un muro de registro al destinatario no impide que el servidor vea la clave: la clave no debería enviarse al servidor. La lectura de MakePwd es pública para el destinatario. Crear y leer no piden cuenta.
Preguntas frecuentes
¿Lo que va detrás de la almohadilla se envía al servidor?
Por defecto, no. RFC 9110 indica que el URI de destino no incluye el fragmento. En Network, la línea de petición del documento no debería mostrar # ni la clave posterior. El servidor, por diseño, solo ve la ruta y ?id=.
¿Por qué no poner la clave detrás del interrogante?
La consulta entra en la línea de petición HTTP. El anfitrión y los registros de acceso pueden verla. Si la clave va en la consulta, «solo cifrado» ya es falso en la capa de logs. Un id de localización puede ir detrás de ?. La clave debería ir detrás de #.
¿Sigue siendo seguro pegar el enlace completo en un chat?
El servidor sigue sin ver la clave. El historial del chat, el ticket y el historial del navegador sí. La URL completa es una credencial al portador. Si tienes que entregarla, confirma que la otra persona recibió la cadena original con la almohadilla, y trátala como algo que vivirá en su historial.
¿Hace falta iniciar sesión para abrir la lectura?
No. La lectura es pública para el destinatario: el id de la consulta pide el cifrado y la clave del fragmento descifra en esta pestaña. MakePwd no tiene cuentas ni almacén de contraseñas. Crear y leer se abren sin registro.
Tres cosas para recordar la próxima vez que envíes un secreto de un solo uso
Primero, mira el carácter, no el eslogan «la clave está en la URL». La consulta va por HTTP. La almohadilla, por lo general, no. Segundo, al crear, confirma que lo saliente es cifrado; al leer, confirma que la línea de petición no incluye lo que va detrás de #. Tercero, antes de entregar el enlace completo, pregunta si acabará en un historial de chat, un ticket o un acortador que tire el hash. Esos dos últimos fallos no tienen que ver con si el servidor es de conocimiento cero.
Si también necesitas comprobar si el texto en claro salió de la pestaña como dato de negocio, eso es la nota anterior: busca un canario en cuerpos de Network y en analytics. Este texto solo convierte «por qué una clave puede ir detrás de la almohadilla» en un juicio que puedes contrastar con las normas y con la línea de petición.