我的服务器依靠 IP 过滤来确保安全。我想知道是否有人可以使用
net.SplitHostPort(r.RemoteAddr)
绕过依赖于远程 IP 过滤的保护
为此,我创建了这个虚拟 http 服务器:
package main
import (
"fmt"
"net"
"net/http"
)
func getHello(w http.ResponseWriter, r *http.Request) {
fmt.Printf("got /hello request\n")
host, _, _ := net.SplitHostPort(r.RemoteAddr)
fmt.Printf("Ip is %s\n", host)
}
func main() {
http.HandleFunc("/hello", getHello)
http.ListenAndServe(":3333", nil)
}
然后我用curl做了一些测试:
curl http://localhost:3333/hello
<- Logs in my server -> Ip is 127.0.0.1
curl http://localhost:3333/hello -H "X-Forwarded-For: 3.3.3.3" -H "Host: 3.3.3.3"
<- Logs in my server -> Ip is 127.0.0.1
这似乎很安全,因为我无法欺骗我的服务器认为请求的 IP 是
3.3.3.3
。
r.RemoteAddr
真的安全并在TCP数据包中查找IP吗?或者有没有办法通过使用标头或伪造数据包来绕过它?
期望通过设置 HTTP 标头来更改远程地址表明了对 TCP/IP 堆栈如何工作的根本误解。没关系 - 这只是让问题变得难以回答。
http.Request.RemoteAddr
由 IP 数据包的标头字段填充:“源 ip 地址”
虽然可以在此标头字段中制作具有任意值的数据包,但建立 TCP 会话需要三向握手。如果服务器尝试回复没有匹配的
active-open
会话的主机,它将被拒绝。
这似乎很安全,因为我无法欺骗我的服务器认为请求的 IP 是 3.3.3.3。
据您所知,您设置的两个标头是众所周知的。
虽然后者(如果存在)可用于了解原始客户端的 IP 地址……它仍然是一个标头。由应用程序来解释它。
根据文档这里,
RemoteAddr 字段被 HTTP 客户端忽略。
仅由 HTTP 服务器通过读取
Source Address
数据包中的 IP
来设置。
Host
和 X-Forwarded-For
是 http
标头,仅在 TCP 握手后传递。因此,在成功握手后,在标头中传递此类信息之前,您的 HTTP 服务器已经获得了 RemoteAddr
。