Подтвердить что ты не робот

Правильный способ получения клиентских IP-адресов из http.Request

Какой правильный способ получить все IP-адреса клиентов от http.Request? В PHP есть много переменных, которые я должен проверить. Это то же самое на Go?

Я обнаружил, что:

req.RemoteAddr

И чувствителен ли запрос? например, x-forwarded-for совпадает с x-forwarded-for и x-forwarded-for? (от req.Header.Get("X-FORWARDED-FOR"))

4b9b3361

Ответ 1

Глядя на http.Request, вы можете найти следующие переменные-члены:

// HTTP defines that header names are case-insensitive.
// The request parser implements this by canonicalizing the
// name, making the first character and any characters
// following a hyphen uppercase and the rest lowercase.
//
// For client requests certain headers are automatically
// added and may override values in Header.
//
// See the documentation for the Request.Write method.
Header Header

// RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for
// logging. This field is not filled in by ReadRequest and
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an "IP:port" address before invoking a
// handler.
// This field is ignored by the HTTP client.
RemoteAddr string

Вы можете использовать RemoteAddr для получения IP-адреса и порта удаленного клиента (формат "IP: порт" ), который является адресом исходного запроса или последнего прокси-сервера (например, балансировщик нагрузки, который живет в перед вашим сервером).

Это все, что у вас есть.

Затем вы можете исследовать заголовки, которые нечувствительны к регистру (согласно приведенной выше документации), что означает, что все ваши примеры будут работать и дают тот же результат:

req.Header.Get("X-Forwarded-For") // capitalisation
req.Header.Get("x-forwarded-for") // doesn't
req.Header.Get("X-FORWARDED-FOR") // matter

Это потому, что внутренне http.Header.Get будет нормализовать ключ для вас. (Если вы хотите получить доступ к карте заголовка напрямую, а не через Get, сначала вам нужно будет использовать http.CanonicalHeaderKey.)

Наконец, "X-Forwarded-For" - это, вероятно, поле, которое вы хотите посмотреть, чтобы получить больше информации о клиентском IP-адресе. Это сильно зависит от программного обеспечения HTTP, используемого на удаленной стороне, хотя клиент может поместить что-нибудь там, если захочет. Также обратите внимание, что ожидаемый формат этого поля представляет собой список адресов IP-адресов, разделенных запятой и пробелом. Вам нужно немного разобрать его, чтобы получить один IP-адрес по вашему выбору (возможно, первый в списке), например:

// Assuming format is as expected
ips := strings.Split("10.0.0.1, 10.0.0.2, 10.0.0.3", ", ")
for _, ip := range ips {
    fmt.Println(ip)
}

будет производить:

10.0.0.1
10.0.0.2
10.0.0.3

Ответ 2

Здесь полностью рабочий пример

package main

import (  
    // Standard library packages
    "fmt"
    "strconv"
    "log"
    "net"
    "net/http"

    // Third party packages
    "github.com/julienschmidt/httprouter"
    "github.com/skratchdot/open-golang/open"
)



// https://blog.golang.org/context/userip/userip.go
func getIP(w http.ResponseWriter, req *http.Request, _ httprouter.Params){
    fmt.Fprintf(w, "<h1>static file server</h1><p><a href='./static'>folder</p></a>")

    ip, port, err := net.SplitHostPort(req.RemoteAddr)
    if err != nil {
        //return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)

        fmt.Fprintf(w, "userip: %q is not IP:port", req.RemoteAddr)
    }

    userIP := net.ParseIP(ip)
    if userIP == nil {
        //return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
        fmt.Fprintf(w, "userip: %q is not IP:port", req.RemoteAddr)
        return
    }

    // This will only be defined when site is accessed via non-anonymous proxy
    // and takes precedence over RemoteAddr
    // Header.Get is case-insensitive
    forward := req.Header.Get("X-Forwarded-For")

    fmt.Fprintf(w, "<p>IP: %s</p>", ip)
    fmt.Fprintf(w, "<p>Port: %s</p>", port)
    fmt.Fprintf(w, "<p>Forwarded for: %s</p>", forward)
}


func main() {  
    myport := strconv.Itoa(10002);


    // Instantiate a new router
    r := httprouter.New()

    r.GET("/ip", getIP)

    // Add a handler on /test
    r.GET("/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
        // Simply write some test data for now
        fmt.Fprint(w, "Welcome!\n")
    })  


    l, err := net.Listen("tcp", "localhost:" + myport)
    if err != nil {
        log.Fatal(err)
    }
    // The browser can connect now because the listening socket is open.


    //err = open.Start("http://localhost:"+ myport + "/test")
    err = open.Start("http://localhost:"+ myport + "/ip")
    if err != nil {
         log.Println(err)
    }

    // Start the blocking server loop.
    log.Fatal(http.Serve(l, r)) 
}

Ответ 3

В PHP есть много переменных, которые я должен проверить. Это то же самое на Go?

Это не имеет никакого отношения к Go (или PHP, если на то пошло). Это зависит от того, что отправляет клиент, прокси, балансировка нагрузки или сервер. Получите тот, который вам нужен, в зависимости от вашей среды.

http.Request.RemoteAddr содержит удаленный IP-адрес. Это может быть или не быть вашим фактическим клиентом.

И чувствителен ли запрос? например, x-forwarded-for совпадает с X-Forwarded-For и X-FORWARDED-FOR? (из req.Header.Get( "X-FORWARDED-FOR" ))

Нет, почему бы не попробовать? http://play.golang.org/p/YMf_UBvDsH

Ответ 4

Вот как я придумала IP

func ReadUserIP(r *http.Request) string {
    IPAddress := r.Header.Get("X-Real-Ip")
    if IPAddress == "" {
        IPAddress = r.Header.Get("X-Forwarded-For")
    }
    if IPAddress == "" {
        IPAddress = r.RemoteAddr
    }
    return IPAddress
}
  • X-Real-Ip - извлекает первый истинный IP (если запросы находятся за несколькими источниками NAT/балансировщиком нагрузки)

  • X-Forwarded-For - если по какой-то причине X-Real-Ip пуст и не возвращает ответ, получите от X-Forwarded-For

  • Удаленный адрес - в крайнем случае (обычно это не надежно, так как это может быть последний IP-адрес или если это пустой HTTP-запрос к серверу, т.е. Нет балансировщика нагрузки)

Ответ 5

Это сработало для меня. Я запустил 8081 и сделал запрос от порта 8080.

fmt.Printf("r: %+v\n", r) // Print all fields that you get in request

Вывод:

r: & {Метод: POST URL:/email Прото: HTTP/1.1 ProtoMajor: 1 ProtoMinor: 1 Заголовок: карта [User-Agent: [Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.11 (KHTML, как и Gecko) Версия /10.0.1 Safari/602.2.11] Accept-Language: [en-us] Accept-Encoding: [gzip, deflate] Соединение: [keep-alive] Accept: [/] Referer: [http://127.0.0.1:8080/] Content-Length: [9] Content-Type: [применение/х-WWW-форм-urlencoded; charset = UTF-8] Происхождение: [http://127.0.0.1:8080]] Тело: 0xc420012800 ContentLength: 9 TransferEncoding: [] Закрыть: false Хост: 127.0.0.1: 8081 Форма: map [] PostForm: map [] MultipartForm: Трейлер: map [] RemoteAddr: 127.0.0.1: 62232 RequestURI:/email TLS: Отменить: ответ: ctx: 0xc420017860}

У рефератора и источника есть мой клиентский IP-адрес.

ip := r.Referer() // Get Referer value
fmt.Println(ip) // print ip

Вывод:

http://127.0.0.1:8080/