El 403 reportaba ip_vista=104.22.14.222, que es un edge de Cloudflare: el tráfico entra por CF y recién ahí por el proxy del hosting, así que la última entrada de X-Forwarded-For es el edge y no quien llama. Se usa CF-Connecting-IP cuando está: la escribe Cloudflare con la IP real y sobrescribe la que mande el cliente. Sin Cloudflare sigue valiendo la última entrada del XFF, como estaba. Queda anotado que todo esto vale mientras el tráfico entre por el proxy: quien pueda pegarle al origen directo puede falsear los dos encabezados, y eso se cierra en la red, no en esta función. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
44 lines
1.6 KiB
Go
44 lines
1.6 KiB
Go
package middlewares
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// IPDelCliente devuelve la IP pública desde la que se hizo la petición.
|
|
//
|
|
// c.IP() no sirve para esto en producción: detrás del proxy del hosting
|
|
// devuelve la IP interna del proxy (10.x.x.x), así que ninguna IP pública
|
|
// autorizada coincidía nunca y toda llave con restricción de IP daba 403.
|
|
//
|
|
// Sin Cloudflare se toma la ÚLTIMA entrada de X-Forwarded-For, no la primera:
|
|
// con un solo proxy adelante, esa es la que escribió el proxy y no la puede
|
|
// falsear quien llama. Si el cliente manda su propio X-Forwarded-For, el proxy
|
|
// le agrega la IP real al final — quedarse con la primera sería creerle al que
|
|
// llama.
|
|
//
|
|
// ponytail: esto vale mientras todo el tráfico entre por el proxy (y por
|
|
// Cloudflare, si está). Quien pueda pegarle al origen directo puede falsear
|
|
// ambos encabezados; si eso pasa a importar, hay que cerrar el origen a las
|
|
// redes del proxy en vez de complicar esta función.
|
|
func IPDelCliente(c *fiber.Ctx) string {
|
|
// Cloudflare adelante: el proxy del hosting ve la IP del edge de CF, así
|
|
// que la última entrada de X-Forwarded-For es 104.x.x.x y no el que llama.
|
|
// CF-Connecting-IP la escribe Cloudflare con la IP real y sobrescribe la
|
|
// que mande el cliente, así que cuando está es la buena.
|
|
if cf := strings.TrimSpace(c.Get("CF-Connecting-IP")); cf != "" {
|
|
return cf
|
|
}
|
|
if xff := c.Get("X-Forwarded-For"); xff != "" {
|
|
partes := strings.Split(xff, ",")
|
|
if ip := strings.TrimSpace(partes[len(partes)-1]); ip != "" {
|
|
return ip
|
|
}
|
|
}
|
|
if real := strings.TrimSpace(c.Get("X-Real-Ip")); real != "" {
|
|
return real
|
|
}
|
|
return c.IP()
|
|
}
|