【问题标题】:How to limit client IP address when using golang http package使用golang http包时如何限制客户端IP地址
【发布时间】:2016-10-20 04:45:56
【问题描述】:

我正在使用 golang http 包。服务器如何限制客户端IP地址?

func (s *Worker) Run(c chan error) {
    apiMux := http.NewServeMux()
    apiMux.HandleFunc("/test", s.test)
    apiMux.HandleFunc("/block/create", s.CreateBlock)
    apiMux.HandleFunc("/block/delete", s.DeleteBlock)

    apiServer := &http.Server{
        Addr:    "0.0.0.0:" + strconv.Itoa(s.ListenPort),
        Handler: apiMux,
    }

    go func() {
        log.Println("Worker listening on " + apiServer.Addr)
        c <- apiServer.ListenAndServe()
    }()
}

【问题讨论】:

标签: http go


【解决方案1】:

您需要做两件事:一是使用中间件处理程序包装您的多路复用器,该处理程序可以预处理您的请求并验证 IP。另一个是获取用户的真实 IP,如果您在防火墙或负载均衡器后面(导致地址始终是 LB 的地址),或者如果您的用户在代理后面,这一点很重要。

至于包装你的多路复用器,这很简单:

apiServer := &http.Server{
    Addr:    "0.0.0.0:8080",
    Handler: http.HandlerFunc( func(w http.ResponseWriter, req *http.Request) {
        // get the real IP of the user, see below
        addr := getRealAddr(req)

       // the actual vaildation - replace with whatever you want
       if (addr != "1.2.3.4") {
            http.Error(w, "Blocked", 401)
            return
        }
        // pass the request to the mux
        apiMux.ServeHTTP(w,req)
    }),
}

我正在附加 getRealAddr 函数,该函数来自一个我在其中执行过类似操作的实际项目:

func getRealAddr(r *http.Request)  string {

    remoteIP := ""
    // the default is the originating ip. but we try to find better options because this is almost
    // never the right IP
    if parts := strings.Split(r.RemoteAddr, ":"); len(parts) == 2 {
        remoteIP = parts[0]
    }
    // If we have a forwarded-for header, take the address from there
    if xff := strings.Trim(r.Header.Get("X-Forwarded-For"), ","); len(xff) > 0 {
        addrs := strings.Split(xff, ",")
        lastFwd := addrs[len(addrs)-1]
        if ip := net.ParseIP(lastFwd); ip != nil {
            remoteIP = ip.String()
        }
    // parse X-Real-Ip header
    } else if xri := r.Header.Get("X-Real-Ip"); len(xri) > 0 {
        if ip := net.ParseIP(xri); ip != nil {
            remoteIP = ip.String()
        }
    }

    return remoteIP

}

至于过滤,它可以基于一组ip,或者CIDR范围,当然这取决于你。

如果您有兴趣,上面的代码来自我编写和使用的 API 构建工具包,名为 Vertex,它内置:https://github.com/EverythingMe/vertex

【讨论】:

  • 为什么用最后一个而不是第一个?
  • @lf215 第一个可能是内部 LAN 地址或类似地址。最后一个应该是您的反向代理或 LB 看到的地址,通常是您想要进行国家/地区过滤等操作的地址,即客户端的 ISP 提供的地址。
  • 引用维基百科关于该主题的内容:The last IP address is always the IP address that connects to the last proxy, which means it is the most reliable source of informationen.wikipedia.org/wiki/X-Forwarded-For#Format
  • 需要注意的一点是,如果运行此代码的机器启用了 ipv6,则地址可能采用 [::]:&lt;port&gt; 形式。例如,当我在本地服务和请求时,r.RemoteAddr 返回[::1]:32445(端口可能会不同)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 2015-03-01
  • 2013-05-01
  • 1970-01-01
  • 2016-02-25
  • 2019-01-16
  • 1970-01-01
相关资源
最近更新 更多