Detect HTTPS interception (#1430)

* WIP: Implement HTTPS interception detection by Durumeric, et. al.

Special thanks to @FiloSottile for guidance with the custom listener.

* Add {{.IsMITM}} context action and {mitm} placeholder

* Improve MITM detection heuristics for Firefox and Edge

* Add tests for MITM detection heuristics

* Improve Safari heuristics for interception detection

* Read ClientHello during first Read() instead of during Accept()

As far as I can tell, reading the ClientHello during Accept() prevents
new connections from being accepted during the read. Since Read() should
be called in its own goroutine, this keeps Accept() non-blocking.

* Clean up MITM detection handler; make possible to close connection

* Use standard lib cipher suite values when possible

* Improve Edge heuristics and test cases

* Refactor MITM checking logic; add some debug statements for now

* Fix bug in MITM heuristic tests and actual heuristic code

* Fix gofmt

* Remove debug statements; preparing for merge
This commit is contained in:
Matt Holt
2017-02-17 14:07:57 -07:00
committed by GitHub
parent cdf7cf5c3f
commit 82cbd7a96b
7 changed files with 811 additions and 2 deletions

View File

@@ -47,6 +47,18 @@ func NewServer(addr string, group []*SiteConfig) (*Server, error) {
}
s.Server.Handler = s // this is weird, but whatever
tlsh := &tlsHandler{next: s.Server.Handler}
s.Server.ConnState = func(c net.Conn, cs http.ConnState) {
// when a connection closes or is hijacked, delete its entry
// in the map, because we are done with it.
if tlsh.listener != nil {
if cs == http.StateHijacked || cs == http.StateClosed {
tlsh.listener.helloInfosMu.Lock()
delete(tlsh.listener.helloInfos, c.RemoteAddr().String())
tlsh.listener.helloInfosMu.Unlock()
}
}
}
// Disable HTTP/2 if desired
if !HTTP2 {
@@ -75,6 +87,10 @@ func NewServer(addr string, group []*SiteConfig) (*Server, error) {
s.Server.TLSConfig.NextProtos = []string{"h2"}
}
if s.Server.TLSConfig != nil {
s.Server.Handler = tlsh
}
// Compile custom middleware for every site (enables virtual hosting)
for _, site := range group {
stack := Handler(staticfiles.FileServer{Root: http.Dir(site.Root), Hide: site.HiddenFiles})
@@ -156,7 +172,10 @@ func (s *Server) Serve(ln net.Listener) error {
// not implement the File() method we need for graceful restarts
// on POSIX systems.
// TODO: Is this ^ still relevant anymore? Maybe we can now that it's a net.Listener...
ln = tls.NewListener(ln, s.Server.TLSConfig)
ln = newTLSListener(ln, s.Server.TLSConfig, s.Server.ReadTimeout)
if handler, ok := s.Server.Handler.(*tlsHandler); ok {
handler.listener = ln.(*tlsHelloListener)
}
// Rotate TLS session ticket keys
s.tlsGovChan = caddytls.RotateSessionTicketKeys(s.Server.TLSConfig)