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>
56 lines
1.5 KiB
Go
56 lines
1.5 KiB
Go
package middlewares
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
func TestIPDelCliente(t *testing.T) {
|
|
casos := []struct {
|
|
nombre string
|
|
xff string
|
|
real string
|
|
cf string
|
|
want string
|
|
}{
|
|
// Con Cloudflare adelante, la última entrada del XFF es el edge de CF
|
|
// (104.x.x.x): la IP real solo está en CF-Connecting-IP.
|
|
{"detrás de cloudflare", "46.202.93.92, 104.22.14.222", "", "46.202.93.92", "46.202.93.92"},
|
|
{"un solo proxy", "46.202.93.92", "", "", "46.202.93.92"},
|
|
// Si quien llama manda su propio X-Forwarded-For, el proxy le agrega la
|
|
// IP real al final. Quedarse con la primera sería dejar que elija su IP.
|
|
{"cliente intentando falsear", "1.2.3.4, 46.202.93.92", "", "", "46.202.93.92"},
|
|
{"con espacios", " 10.0.0.1 , 46.202.93.92 ", "", "", "46.202.93.92"},
|
|
{"sin xff, con x-real-ip", "", "46.202.93.92", "", "46.202.93.92"},
|
|
}
|
|
|
|
app := fiber.New()
|
|
app.Get("/ip", func(c *fiber.Ctx) error {
|
|
return c.SendString(IPDelCliente(c))
|
|
})
|
|
|
|
for _, cs := range casos {
|
|
req := httptest.NewRequest("GET", "/ip", nil)
|
|
if cs.xff != "" {
|
|
req.Header.Set("X-Forwarded-For", cs.xff)
|
|
}
|
|
if cs.real != "" {
|
|
req.Header.Set("X-Real-Ip", cs.real)
|
|
}
|
|
if cs.cf != "" {
|
|
req.Header.Set("CF-Connecting-IP", cs.cf)
|
|
}
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", cs.nombre, err)
|
|
}
|
|
buf := make([]byte, 64)
|
|
n, _ := resp.Body.Read(buf)
|
|
if got := string(buf[:n]); got != cs.want {
|
|
t.Errorf("%s: IPDelCliente = %q, want %q", cs.nombre, got, cs.want)
|
|
}
|
|
}
|
|
}
|