Codificador / Decodificador de entidades HTML

Convierte caracteres especiales en entidades HTML y viceversa.

Ningún dato sale de tu dispositivo

Entidades HTML habituales

CarácterEntidadNuméricoDescripción
&&&Ampersand
<&lt;&#60;Menor que
>&gt;&#62;Mayor que
"&quot;&#34;Comilla doble
'&apos;&#39;Apóstrofo
 &nbsp;&#160;Espacio indivisible
©&copy;&#169;Copyright
®&reg;&#174;Marca registrada
&trade;&#8482;Marca comercial
&euro;&#8364;Signo del euro

¿Por qué usar las entidades HTML?

Caracteres como <, > y & tienen un significado especial en HTML. Si los incluyes literalmente en tu HTML, el navegador los interpreta como código, no como contenido. Codificar estos caracteres como entidades evita problemas de renderizado y vulnerabilidades de scripting entre sitios (XSS).

Preguntas frecuentes

¿Cuál es la diferencia entre entidades con nombre y numéricas?

Las entidades con nombre usan nombres descriptivos (&amp;, &copy;) mientras que las entidades numéricas usan puntos de código Unicode (&#38;, &#169;). Las dos se muestran igual. Las entidades con nombre son más legibles; las entidades numéricas funcionan para cualquier carácter Unicode.

¿Debo codificar todos los caracteres especiales?

Como mínimo, debes codificar &, <, > y " en el contenido HTML y los valores de atributo. Los navegadores modernos gestionan la mayoría de los demás caracteres de forma nativa si tu documento usa la codificación UTF-8.

Tres formas, un carácter

Una «entidad» HTML, formalmente una referencia de carácter: es una secuencia de escape que representa un carácter usando una secuencia de caracteres ASCII normales. El HTML Living Standard define tres formas sintácticas concretas:

Las tres formas son intercambiables al renderizarse: &copy;, &#169; y &#xA9; producen todas el carácter visible © porque todas se resuelven al punto de código Unicode U+00A9. La elección entre ellas es una cuestión de legibilidad del código fuente, no de comportamiento del navegador. El hexadecimal tiende a coincidir con las tablas de Unicode publicadas (que usan la notación U+XXXX), así que &#x2665; está más cerca de la notación oficial U+2665 que &#9829;. Las referencias numéricas funcionan para cualquier carácter Unicode, incluidos los emojis del plano astral: &#x1F600; se renderiza como 😀 (U+1F600 GRINNING FACE).

Por qué existen las entidades

Tres razones históricas y prácticas distintas:

  1. Para escapar los caracteres que tienen un significado sintáctico en HTML. El analizador usa ciertos caracteres ASCII como símbolos de control. < abre una etiqueta, > cierra una, & introduce una referencia, y los caracteres de comillas delimitan los valores de atributo. Si quieres que cualquiera de ellos aparezca como texto literal, debes escaparlo.
  2. Para representar caracteres no disponibles en la codificación del documento. Antes de que UTF-8 se volviera universal en la web (solo superó el 50 % alrededor de 2010), la mayoría del HTML se servía como US-ASCII, ISO-8859-1 o Windows-1252. En esas codificaciones de un solo byte, los caracteres como ©, €, ≈ o α simplemente no podían expresarse con un byte literal. Escribir &copy;, &euro; o &#8776; era la única forma de alcanzar esos puntos de código.
  3. Para señalar la intención del autor en los caracteres invisibles o ambiguos. Incluso en una página UTF-8, un espacio de no separación literal (U+00A0) es visualmente idéntico a un espacio normal; escribir &nbsp; hace que la intención sea obvia para cualquiera que lea el código fuente.

El W3C ahora recomienda usar caracteres Unicode literales siempre que sea posible en lugar de entidades, «por accesibilidad y legibilidad». Las entidades siguen siendo útiles para los cinco escapes obligatorios, además de los caracteres genuinamente invisibles o ambiguos.

Los cinco grandes

Los cinco caracteres que debes escapar sin falta al insertar contenido no confiable en HTML son <, >, &, " y '. La Cross-Site Scripting Prevention Cheat Sheet de OWASP los enumera como el conjunto mínimo de escapes obligatorios:

CarácterCon nombreDecimalHexadecimal
<&lt;&#60;&#x3C;
>&gt;&#62;&#x3E;
&&amp;&#38;&#x26;
"&quot;&#34;&#x22;
'&apos; / &#39;&#39;&#x27;

La regla general: siempre que coloques texto no confiable en una salida HTML, escapa primero estos cinco caracteres. No hacerlo es la causa raíz de la inmensa mayoría de las vulnerabilidades XSS almacenadas y reflejadas.

La trampa del apóstrofo

&apos; no forma parte de HTML 4; originalmente lo definía solo XML 1.0 y se heredó en XHTML 1.0. Internet Explorer anterior a la versión 9 (lanzada en 2011) se negaba a renderizarlo como ' y mostraba el texto literal &apos;. La entidad se añadió específicamente a HTML5 y ahora es segura en todos los navegadores modernos, pero para una compatibilidad máxima entre navegadores y entre especificaciones, OWASP y la mayoría de las bibliotecas de saneamiento empresariales todavía recomiendan emitir &#39; en lugar de &apos; al escapar las comillas simples, particularmente en el código crítico para la seguridad.

Cuándo codificar y cuándo no

La decisión de codificación depende de dónde va a aterrizar el texto en la salida, no de lo que contiene. Este es el punto peor entendido de la seguridad de HTML. La guía de OWASP distingue los contextos:

Cada contexto tiene sus propias reglas de escape. Mezclarlas es en sí mismo una vulnerabilidad; por ejemplo, codificar por porcentajes un < a %3C no protege contra el XSS en el contexto de contenido de elemento HTML, donde %3C es solo el texto literal %3C.

Evita la doble codificación. Un error común es escapar los datos cuando se leen en el sistema, otra vez cuando se almacenan, otra vez cuando se leen y otra vez cuando se renderizan. El resultado: el usuario escribió 5 < 10, la base de datos almacena 5 &amp;lt; 10, la página renderiza 5 &lt; 10 en lugar del original. La disciplina es: almacena Unicode en bruto, codifica una vez, en el momento de la salida, para el contexto específico.

Codificación HTML frente a codificación de URL

Dos sistemas de escape diferentes para dos contextos diferentes, confundidos todo el tiempo:

Entidad HTMLURL / porcentaje
EstándarHTML Living StandardRFC 3986
Formato&name; o &#NN;%HH (byte hex)
ContextoMarcado HTML, cuerpos de elementos y atributosURL, cadenas de consulta, cuerpos de petición codificados en formulario
Espacio&nbsp; (de no separación), nunca un espacio normal%20 o +
Función JS- (lo gestiona el analizador)encodeURIComponent() / encodeURI()

Una URL dentro de un valor de atributo HTML recibe ambos escapes superpuestos: primero la codificación por porcentajes para los caracteres ilegales en URL, luego la codificación HTML para cualquier & < > " en la URL resultante. Por esto los ampersands de las cadenas de consulta dentro de un atributo href se convierten en &amp; en la serialización HTML.

Una breve historia

HTML 2.0 (RFC 1866, 1995) heredó el mecanismo de entidades de SGML con unas 50 entidades con nombre para ISO Latin 1. HTML 3.2 (W3C, enero de 1997) añadió las entidades matemáticas y de símbolos. HTML 4.01 (W3C, diciembre de 1999) finalizó tres conjuntos de entidades (Latin-1, Special y Symbol) que sumaban 252 entidades con nombre, que es el origen de la cifra «252» que todavía se ve en los tutoriales más antiguos. HTML5 / WHATWG (Living Standard, en curso) absorbió y amplió drásticamente la tabla a más de 2000 entradas, principalmente para cubrir MathML y un conjunto de Unicode más amplio. XML 1.0 (1998) define su propio conjunto mínimo de solo los cinco grandes (&lt; &gt; &amp; &quot; &apos;); ese conjunto mínimo es el origen de &apos;.

Más preguntas

En el código moderno, ¿qué debería usar en realidad?

El código de producción generalmente no implementa a mano la codificación de entidades, sino que llama a una biblioteca. DOMPurify para el saneamiento de HTML del lado del cliente. html.escape() en la biblioteca estándar de Python. htmlspecialchars() en PHP. html/template en Go (autoescape activado por defecto). OWASP Java Encoder para Java. En React, escribir <div>{userInput}</div> escapa automáticamente; la vía de escape dangerouslySetInnerHTML se llama así para desalentar su uso casual. Un codificador independiente como este es útil como herramienta de comprobación o depuración, no como sustituto de esas bibliotecas.

¿Qué pasa con las etiquetas dentro de las plantillas de correo?

Los clientes de correo más antiguos (Outlook en particular) interpretan un & sin codificar como un atributo mal formado y pueden eliminar el marcado circundante. Los desarrolladores de correo HTML aprenden a codificar como entidad cada carácter especial de forma defensiva. Lo mismo se aplica a los sistemas de estilo BBCode de los foros que reescriben el contenido antes de almacenarlo; las idas y vueltas pueden introducir entidades literales inesperadas.

¿Qué diferencia hay entre textContent e innerHTML en JavaScript?

La regla de prevención de XSS más importante en JavaScript puro: usa element.textContent = userInput en lugar de element.innerHTML = userInput. Establecer textContent escribe la cadena como texto literal: el navegador gestiona todo el escape internamente. Establecer innerHTML analiza la cadena como HTML, ejecutando cualquier etiqueta <script> o atributo de manejador de eventos que contenga. Si el marcado es realmente necesario, usa una biblioteca como DOMPurify para sanearlo primero.

¿Puede el codificador manejar emojis?

Sí, mediante referencias numéricas. No hay entidades con nombre para los emojis, todos usan la forma numérica. &#x1F600; se renderiza como 😀, &#x2764;&#xFE0F; como el corazón rojo ❤️ (el punto de código del corazón más el selector de presentación de emoji). El navegador gestiona internamente la conversión implícita del par sustituto UTF-16; no deberías escribir las mitades sustitutas manualmente.

¿Se envía algo a un servidor?

No. La codificación y la decodificación son transformaciones de cadena de función pura que se ejecutan íntegramente en tu navegador mediante JavaScript. Nada de tu entrada se sube; la página funciona sin conexión una vez cargada. Esto importa porque los codificadores basados en la nube que hacen ida y vuelta con tu carga útil de prueba pueden convertirse ellos mismos en un vector de XSS si el sitio de prueba está comprometido.

Herramientas relacionadas