为了账号安全,请及时绑定邮箱和手机立即绑定

Golang ReverseProxy 与 Apache2 SNI/主机名错误

Golang ReverseProxy 与 Apache2 SNI/主机名错误

Go
杨__羊羊 2021-12-07 10:10:41
我正在用 Go 编写我自己的 ReverseProxy。ReverseProxy 应该连接我的 go-webserver 和我的 apache2 webserver。但是当我在另一个 IP 地址上运行我的反向代理时,当反向代理将请求发送到 apache 时,我的 Apache2 网络服务器在我的 apache 日志文件中出现以下错误。"Hosname xxxx provided via sni and hostname xxxx2 provided via http are different"我的反向代理和 apache-webserver 在 https 上运行。这里有一些代码:func (p *Proxy) directorApache(req *http.Request) {    mainServer := fmt.Sprintf("%s:%d", Config.HostMain, Config.PortMain)    req.URL.Scheme = "https"    req.URL.Host = mainServer}func (p *Proxy) directorGo(req *http.Request) {    goServer := fmt.Sprintf("%s:%d", Config.GoHost, Config.GoPort)    req.URL.Scheme = "http"    req.URL.Host = goServer}func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {    fmt.Println(req.URL.Path)    if p.isGoRequest(req) {        fmt.Println("GO")        p.goProxy.ServeHTTP(rw, req)        return    }    p.httpProxy.ServeHTTP(rw, req)}func main() {    var configPath = flag.String("conf", "./configReverse.json", "Path to the Json config file.")    flag.Parse()    proxy := New(*configPath)    cert, err := tls.LoadX509KeyPair(Config.PathCert, Config.PathPrivateKey)    if err != nil {        log.Fatalf("server: loadkeys: %s", err)    }    config := tls.Config{InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}}    listener, err := net.Listen("tcp",    net.JoinHostPort(proxy.Host, strconv.Itoa(proxy.Port)))    if err != nil {        log.Fatalf("server: listen: %s", err)    }    log.Printf("server: listening on %s")    proxy.listener = tls.NewListener(listener, &config)    serverHTTPS := &http.Server{        Handler:   proxy.mux,        TLSConfig: &config,    }    if err := serverHTTPS.Serve(proxy.listener); err != nil {        log.Fatal("SERVER ERROR:", err)    }}也许有人对这个问题有想法。
查看完整描述

1 回答

?
DIEA

TA贡献1820条经验 获得超2个赞

简短示例

假设您正在向https://your-proxy.local. 您的请求处理程序采用该http.Request结构并将其URL字段重写为https://your-apache-backend.local.

您没有考虑的是,原始 HTTP 请求还包含一个Host标头 ( Host: your-proxy.local)。将相同的请求传递给 时http://your-apache-backend.local,该请求中的Host标头仍然显示Host: your-proxy.local. 这就是 Apache 所抱怨的。

解释

当您使用带有服务器名称指示 (SNI) 的 TLS 时,请求主机名不仅会用于 DNS 解析,还会用于选择用于建立 TLS 连接的 SSL 证书。Host另一方面,Apache 使用HTTP 1.1标头来区分多个虚拟主机。两个名称必须匹配Apache HTTPD wiki 中也提到了这个问题:

SNI/请求主机名不匹配,或 SNI 提供主机名而请求不提供。

这是浏览器错误。Apache 会以 400 类型的错误拒绝请求。

解决方案

还要重写Host标题。如果要保留原始Host标头,可以将其存储在X-Forwarded-Host标头中(这是一个非标准标头,但它广泛用于反向代理):

func (p *Proxy) directorApache(req *http.Request) {

    mainServer := fmt.Sprintf("%s:%d", Config.HostMain, Config.PortMain)

    req.URL.Scheme = "https"

    req.URL.Host = mainServer

    req.Header.Set("X-Forwarded-Host", req.Header().Get("Host"))

    req.Host = mainServer

}


查看完整回答
反对 回复 2021-12-07
  • 1 回答
  • 0 关注
  • 149 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信