带有Apache2 SNI/主机名错误的Golang ReverseProxy [英] Golang ReverseProxy with Apache2 SNI/Hostname error

查看:300
本文介绍了带有Apache2 SNI/主机名错误的Golang ReverseProxy的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用Go编写自己的ReverseProxy.ReverseProxy应该连接我的go-web服务器和我的apache2 web服务器.但是,当我在另一个IP地址上运行反向代理时,然后在我的Apache2网络服务器上,当反向代理将请求发送到apache时,我的apache-log文件中出现以下错误.

i am writing my own ReverseProxy in Go.The ReverseProxy should connect my go-webserver and my apache2 webserver. But when I run my reverseproxy on another IP-Adress then my Apache2 webserver I got following error in my apache-logfile, when the reverseproxy sends the request to apache.

"Hosname xxxx provided via sni and hostname xxxx2 provided via http are different"

我的反向代理和运行在https上的apache-webserver.

My Reverse Proxy and apache-webserver running on 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)
    }
}

也许有人对这个问题有个想法.

Perhaps someone has a idea about that issue.

推荐答案

简短示例

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

Short example

Say you're starting an HTTP request to https://your-proxy.local. Your request handler takes the http.Request struct and rewrites its URL field to https://your-apache-backend.local.

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

What you have not considered, is that the original HTTP request also contained a Host header (Host: your-proxy.local). When passing that same request to http://your-apache-backend.local, the Host header in that request still says Host: your-proxy.local. And that's what Apache is complaining about.

当您使用带服务器名称指示(SNI)的TLS时,请求主机名不仅将用于DNS解析,还将选择用于建立TLS连接的SSL证书.另一方面,HTTP 1.1 Host标头用于通过Apache区分多个虚拟主机.这两个名称必须匹配. Apache HTTPD Wiki :

As you're using TLS with Server Name Indication (SNI), the request hostname will not only be used for DNS resolution, but also to select the SSL certificate that should be used to establish the TLS connection. The HTTP 1.1 Host header on the other hand is used to distinguish several virtual hosts by Apache. Both names must match. This issue is also mentioned in the Apache HTTPD wiki:

SNI/请求主机名不匹配,或者SNI提供的主机名与请求不匹配.

这是浏览器错误. Apache将拒绝该请求,并显示400类型的错误.

This is a browser bug. Apache will reject the request with a 400-type error.

解决方案

也重写Host标头.如果要保留原始的Host标头,则可以将其存储在X-Forwarded-Host标头中(这是非标准标头,但是在反向代理中广泛使用):

Solution

Also rewrite the Host header. If you want to preserve the original Host header, you can store it in an X-Forwarded-Host header (that's a non-standard header, but it's widely used in reverse proxies):

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
}

这篇关于带有Apache2 SNI/主机名错误的Golang ReverseProxy的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆