
En resumen
Una dirección IPv4 es un número de 32 bits. La notación decimal con puntos es solo la forma más común de escribirlo, y los parsers de URL siguen aceptando formas decimales, octales y hexadecimales con una a cuatro partes. La comparación de cadenas no las normaliza, y así se saltan las listas de permitidos.
Una dirección IPv4 es un número de 32 bits. La forma conocida, 192.168.1.1, es solo una manera de escribir ese número: cuatro octetos decimales separados por puntos. Hay al menos otras cinco formas de llegar a los mismos 32 bits, y los navegadores, las librerías de URL y las herramientas de línea de comandos todavía aceptan casi todas.
No es una simple curiosidad. Si tu aplicación bloquea una dirección comparando la cadena que escribió el usuario, el atacante elige cuál de las formas equivalentes enviar. Esta guía explica qué significan las notaciones, demuestra el comportamiento con parsers reales y muestra el paso de normalización que cierra el hueco.
01Una dirección IPv4 es un solo número de 32 bits
La notación decimal con puntos son dígitos en base 256. Cada uno de los cuatro octetos lleva 8 bits, y el primero es el más significativo. Si lees el conjunto como un único entero, obtienes un valor entre 0 y 4294967295.
| Decimal con puntos | Entero | Hexadecimal |
|---|---|---|
| 0.0.0.0 | 0 | 0x00000000 |
| 10.0.0.1 | 167772161 | 0x0a000001 |
| 127.0.0.1 | 2130706433 | 0x7f000001 |
| 169.254.169.254 | 2852039166 | 0xa9fea9fe |
| 192.168.1.1 | 3232235777 | 0xc0a80101 |
| 255.255.255.255 | 4294967295 | 0xffffffff |
Todas las demás notaciones de este artículo son una codificación distinta de uno de esos enteros. Esa es la idea que vuelve predecible todo el tema.
02Convertir decimal con puntos a entero a mano
La conversión es posicional, igual que en decimal. Multiplica cada octeto por 256 elevado a su posición desde la derecha y suma:
192.168.1.1
192 x 256^3 = 192 x 16777216 = 3221225472
168 x 256^2 = 168 x 65536 = 11010048
1 x 256^1 = 1 x 256 = 256
1 x 256^0 = 1 x 1 = 1
----------
3232235777
Para 127.0.0.1 la misma aritmética da 2130706433, el número del título. Ambos se verificaron el 2026-10-04 con Python 3:
python3 -c "import ipaddress; print(int(ipaddress.IPv4Address('192.168.1.1')),
int(ipaddress.IPv4Address('127.0.0.1')))"
La dirección inversa se lee más rápido en hexadecimal. Divide el valor de 32 bits en cuatro bytes y convierte cada byte a decimal: 0xc0a80101 es c0, a8, 01, 01, o sea 192, 168, 1, 1.
03Las notaciones heredadas que un parser de URL acepta
La RFC 3986 es estricta. Su gramática permite exactamente cuatro octetos decimales sin ceros iniciales, y sus autores sabían que las implementaciones no eran tan estrictas: la especificación tiene una sección entera sobre formatos raros de dirección IP, advirtiendo que rutinas de plataforma como gethostbyname e inet_aton aceptan muchas más formas de las que describe la gramática.
El estándar WHATWG URL, que implementan los navegadores, escribe esa permisividad como algoritmo. El parser de host divide la entrada por puntos y acepta de una a cuatro partes:
- Cuatro partes: cada una es un octeto, de izquierda a derecha.
- Tres partes: las dos primeras son octetos y la última se convierte en un valor de 16 bits en los dos bytes finales.
- Dos partes: la primera es un octeto y la última se convierte en un valor de 24 bits en los tres bytes finales.
- Una parte: el valor es la dirección completa de 32 bits.
Cada parte se analiza después como número con prefijos estilo C: un 0x inicial significa hexadecimal, un 0 inicial significa octal y cualquier otra cosa es decimal. Una parte mayor que 255 solo se permite en la última posición, y la última parte debe caber en los bytes restantes.
Eso explica todas las formas. El número único 2130706433 es la dirección completa. 0x7f.1 es el hexadecimal 0x7f seguido de 1, que rellena los tres bytes restantes. 017700000001 es octal para el mismo valor. 0300.0250.0.1 es 192.168.0.1 porque 0300 y 0250 son octales. Ninguna es una dirección distinta.
Una consecuencia de la regla del cero inicial sorprende a mucha gente: en un parser de URL, 010.1.1.1 no es 10.1.1.1, es 8.1.1.1. Estas reglas llevan tanto tiempo en producción que cambiarlas rompería sitios reales, y por eso existe el algoritmo de compatibilidad.
04Verificado: la misma dirección escrita de cinco formas
Las salidas siguientes vienen de tres parsers distintos, ejecutados todos el 2026-10-04. Node.js 24.14.1 implementa el estándar WHATWG URL:
node -e "for (const s of ['http://2130706433/','http://0x7f.1/',
'http://017700000001/','http://127.1/']) console.log(s, new URL(s).hostname)"
http://2130706433/ -> 127.0.0.1
http://0x7f.1/ -> 127.0.0.1
http://017700000001/ -> 127.0.0.1
http://127.1/ -> 127.0.0.1
El socket.inet_aton de Python, que refleja el comportamiento de la librería C que advertía la RFC, coincide:
socket.inet_aton('2130706433') -> 7f000001
socket.inet_aton('0x7f000001') -> 7f000001
socket.inet_aton('017700000001') -> 7f000001
socket.inet_aton('127.1') -> 7f000001
Y a la capa de red le da igual cómo se escribió la dirección. Con un servidor HTTP desechable escuchando en 127.0.0.1 en el puerto 8099, todas las formas devolvieron HTTP 200:
curl http://127.0.0.1:8099/ -> HTTP 200
curl http://2130706433:8099/ -> HTTP 200
curl http://0x7f.1:8099/ -> HTTP 200
curl http://017700000001:8099/ -> HTTP 200
curl http://127.1:8099/ -> HTTP 200
El último paso es el que importa. La notación heredada no es una curiosidad del navegador: es una conexión real a un socket real.
05Por qué esto es un problema de seguridad
Si una aplicación decide si una petición está permitida comparando la cadena del host contra una lista, el atacante controla la codificación. Un filtro que bloquea 127.0.0.1 y localhost no bloquea 2130706433, y uno que bloquea 169.254.169.254 no bloquea 2852039166.
La RFC 3986 explica el riesgo en su sección de direcciones raras: estos formatos pueden convertirse en un problema de seguridad si una aplicación intenta filtrar el acceso según la dirección IP en formato de cadena literal, y la recomendación es convertir los literales a forma numérica y filtrar por el número.
El patrón aparece en defensas contra SSRF, listas de permitidos de webhooks, filtros de proxy de imágenes y validación de redirecciones. La lista de bloqueo suele ser correcta en intención y errónea en implementación, porque trata un número de 32 bits como una cadena.
Una lista de bloqueo de cadenas no es una lista de bloqueo de direcciones.
127.0.0.1, 127.1, 2130706433, 0x7f.1 y 017700000001 son cinco codificaciones de una sola dirección. También lo son 169.254.169.254 y 2852039166. Si tu filtro solo conoce la primera forma de cada pareja, no funciona.
06Normaliza antes de filtrar
La solución es un paso de canonicalización: convierte el host en una dirección o un entero y compara ese valor con tus reglas. Nunca compares la cadena en crudo.
Los parsers estrictos lo facilitan porque rechazan directamente las formas ambiguas. El módulo ipaddress de Python acepta decimal con puntos y enteros, pero lanza excepción con las formas heredadas, y net.isIP de Node devuelve 0 para todas ellas:
| Entrada | Python ipaddress.ip_address | Node net.isIP |
|---|---|---|
| 127.0.0.1 | 127.0.0.1 | 4 |
| 2130706433 | ValueError | 0 |
| 0x7f.1 | ValueError | 0 |
| 017700000001 | ValueError | 0 |
| 127.1 | ValueError | 0 |
Esa diferencia es justamente el motivo de usar un parser estricto. Un valor que falla la comprobación estricta no es algo que debas pasar a inet_aton con la esperanza de que salga bien: es un motivo para rechazar la petición.
Para un código existente, la secuencia práctica es:
- Analiza la URL con el parser de URL de tu plataforma, no partiendo cadenas a mano.
- Toma el hostname analizado, que el estándar de URL ya ha normalizado a un literal IPv4 canónico.
- Convierte ese literal en un entero o un objeto de dirección.
- Compara contra tu lista de permitidos y de bloqueo como números, incluyendo los rangos privado, loopback y link-local.
- Resuelve el DNS y vuelve a comprobar, porque un nombre de host puede apuntar a una dirección bloqueada.
Los pasos 4 y 5 son donde fallan la mayoría de las defensas SSRF en la práctica. Canonicalizar una dirección solo sirve si la comparación ocurre sobre la forma canónica, y comprobar el hostname no significa nada si la petición lo vuelve a resolver después.
07Convertir entre las formas
El Conversor de bases numéricas de UrsaKit es la forma rápida de ver la relación entre notaciones sin ejecutar código.
- Pega el entero, por ejemplo 2130706433, en el campo Value.
- Pon From base en 10.
- Deja To base en 16, o cámbialo a 2 u 8 para ver el patrón de bits.
- Pulsa Convert. El panel de resultado muestra binario, octal, decimal y hexadecimal a la vez.
- Copia el valor hexadecimal y divídelo en parejas: 7f 00 00 01 es 127.0.0.1.
El conversor es exacto para enteros de cualquier tamaño, así que no redondeará un valor de 32 bits a coma flotante como podría hacer una calculadora improvisada. Cuando lo que revisas es un filtro y no un valor, un probador de regex muestra qué coincide de verdad tu patrón, y un decodificador de URL resuelve el porcentaje antes de comparar, porque %31%32%37... es otra forma de esconder la misma cadena.
| Síntoma | Causa | Solución |
|---|---|---|
| La lista de bloqueo no ve una petición a loopback | Dirección escrita como entero u octal | Normaliza a entero antes de comparar |
| 010.1.1.1 no se comporta como 10.1.1.1 | El cero inicial significa octal al analizar la URL | Rechaza ceros iniciales y exige cuatro octetos canónicos |
| El host pasa el filtro y luego resuelve a otro sitio | El filtro miró el nombre, no la dirección resuelta | Resuelve primero, filtra después y fija la conexión a la dirección comprobada |
| Dos logs muestran hosts distintos para una petición | Cada capa imprimió su propia forma normalizada | Registra el valor canónico que usó el filtro |
08Fuentes
- RFC 3986 — Uniform Resource Identifier (URI): Generic Syntax, secciones 3.2.2 y 7.4 (fecha de consulta: 2026-10-04)
- WHATWG URL Standard — Host parsing y el parser IPv4 (fecha de consulta: 2026-10-04)
- Documentación de Python — módulo ipaddress (fecha de consulta: 2026-10-04)
Convierte un entero IPv4 a hexadecimal, octal y binario, exacto para enteros de cualquier tamaño y todo en el navegador.
Conversor de bases numéricasPreguntas frecuentes
¿Qué es la notación decimal de IPv4?
Es el valor entero de 32 bits de una dirección IPv4, escrito sin puntos. 127.0.0.1 es 2130706433, porque los cuatro octetos forman un solo número en base 256.
¿Por qué 2130706433 abre 127.0.0.1?
Los parsers de URL admiten un formato IPv4 heredado que acepta un único número decimal como la dirección completa de 32 bits. Los navegadores y las herramientas de línea de comandos lo heredaron, así que el host resuelve a 127.0.0.1.
¿Por qué 017700000001 significa 127.0.0.1?
El formato heredado permite prefijos numéricos estilo C en cada parte: un 0 inicial significa octal y un 0x inicial significa hexadecimal. 017700000001 es la forma octal del mismo valor de 32 bits.
¿010.1.1.1 es lo mismo que 10.1.1.1?
No. En el formato heredado de URL un cero inicial convierte esa parte en octal, así que 010 es 8 y la dirección es 8.1.1.1. La gramática dec-octet de la RFC 3986 no permite ceros iniciales en absoluto.
¿Cómo normalizo una dirección IP de forma segura?
Conviértela en un número o en un objeto de dirección y compara el valor numérico. Los parsers estrictos como ipaddress.ip_address de Python o net.isIP de Node rechazan las formas heredadas, mientras que inet_aton y los parsers de URL las aceptan.
¿2852039166 es una dirección IP válida?
Es la forma decimal de 169.254.169.254, la dirección link-local que suelen usar los metadatos de instancia en la nube. Cualquier filtro que bloquee la cadena con puntos pero no el entero deja ese endpoint accesible.
¿Por qué los navegadores siguen aceptando estos formatos?
El estándar WHATWG URL especifica el algoritmo paso a paso que acepta de una a cuatro partes en decimal, octal o hexadecimal. Existe por compatibilidad web con cómo los navegadores han analizado los hosts históricamente.
Artículos relacionados
- Cómo elegir el código de estado HTTP correcto en una API
El tratamiento de direcciones convive con redirecciones y cabeceras, donde los huecos de normalización se vuelven fallos de seguridad.
- Grupos, lookarounds y backtracking en regex, explicados
Casi todos los filtros de IP son expresiones regulares. Aquí se ve por qué coincidir con el texto no es coincidir con el valor.
Herramientas relacionadas
- Conversor de bases numéricas
Decimal, hexadecimal, octal y binario uno al lado del otro.
- Probador de regex
Comprueba qué coincide de verdad tu patrón de filtrado de IP.
- Comparador de textos
Compara el host original con su forma normalizada.
- Decodificador de URL
Decodifica el porcentaje antes de comparar nada.