Use CNAME for SNI check on host header

Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
This commit is contained in:
Ludovic Fernandez 2022-02-14 17:18:08 +01:00 committed by GitHub
parent e97aa6515b
commit d9fbb5e25c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 192 additions and 93 deletions

View file

@ -5,12 +5,11 @@ import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"strings"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/snicheck"
"github.com/traefik/traefik/v2/pkg/rules"
"github.com/traefik/traefik/v2/pkg/server/provider"
tcpservice "github.com/traefik/traefik/v2/pkg/server/service/tcp"
@ -161,38 +160,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
}
}
sniCheck := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if req.TLS == nil {
handlerHTTPS.ServeHTTP(rw, req)
return
}
host, _, err := net.SplitHostPort(req.Host)
if err != nil {
host = req.Host
}
host = strings.TrimSpace(host)
serverName := strings.TrimSpace(req.TLS.ServerName)
// Domain Fronting
if !strings.EqualFold(host, serverName) {
tlsOptionHeader := findTLSOptionName(tlsOptionsForHost, host, true)
tlsOptionSNI := findTLSOptionName(tlsOptionsForHost, serverName, false)
if tlsOptionHeader != tlsOptionSNI {
log.WithoutContext().
WithField("host", host).
WithField("req.Host", req.Host).
WithField("req.TLS.ServerName", req.TLS.ServerName).
Debugf("TLS options difference: SNI=%s, Header:%s", tlsOptionSNI, tlsOptionHeader)
http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest)
return
}
}
handlerHTTPS.ServeHTTP(rw, req)
})
sniCheck := snicheck.New(tlsOptionsForHost, handlerHTTPS)
router.HTTPSHandler(sniCheck, defaultTLSConf)
@ -321,44 +289,3 @@ func (m *Manager) buildTCPHandler(ctx context.Context, router *runtime.TCPRouter
return tcp.NewChain().Extend(*mHandler).Then(sHandler)
}
func findTLSOptionName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
name := findTLSOptName(tlsOptionsForHost, host, fqdn)
if name != "" {
return name
}
name = findTLSOptName(tlsOptionsForHost, strings.ToLower(host), fqdn)
if name != "" {
return name
}
return traefiktls.DefaultTLSConfigName
}
func findTLSOptName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
tlsOptions, ok := tlsOptionsForHost[host]
if ok {
return tlsOptions
}
if !fqdn {
return ""
}
if last := len(host) - 1; last >= 0 && host[last] == '.' {
tlsOptions, ok = tlsOptionsForHost[host[:last]]
if ok {
return tlsOptions
}
return ""
}
tlsOptions, ok = tlsOptionsForHost[host+"."]
if ok {
return tlsOptions
}
return ""
}