Hello all, Now that the MITM CVEs are published [1], I wanted to share my wishlist of things that would have made those attacks difficult/impossible to pull off.
= Implicit TLS = The frontend/backend protocol uses a STARTTLS-style negotiation, which has had a fair number of implementation vulnerabilities in the SMTP space [2] and is where I got the idea for the attacks to begin with. There is a large amount of plaintext traffic on the wire that happens before either party trusts the other, and there is plenty of code that touches that untrusted traffic. An implicit TLS flow would put the TLS handshake at the very beginning of the connection, before any of the frontend/backend protocol is spoken on the wire. (You all have daily experience with this flow, by way of HTTPS.) So a verify-full client would know that the server is the expected recipient, and that the connection is encrypted, before ever sending a single byte of Postgres-specific communication, and before receiving potential error messages. Similarly, a clientcert=verify-* server would have already partially authenticated the client before ever receiving a startup packet, and it can trust that any messages sent during the handshake are received without tampering. This has downsides. Backwards compatibility tends to reintroduce downgrade attacks, which defeats the goal of implicit TLS. So DBAs would probably have to either perform a hard cutover to the new system (with all-new clients ready to go), or else temporarily introduce a new port for the implicit TLS mode (similar to HTTP/HTTPS separation) while older clients are migrated. And obviously this doesn't help you if you're already using a different form of encryption (GSSAPI). I'm ignorant of the state of the art for implicit encryption using that method. But for DBAs who are already deploying TLS as their encryption layer and want to force its use for every client, I think this would be a big step forward. = Client-Side Auth Selection = The second request is for the client to stop fully trusting the server during the authentication phase. If I tell libpq to use a client certificate, for example, I don't think the server should be allowed to extract a plaintext password from my environment (at least not without my explicit opt-in). Auth negotiation has been proposed a couple of times on the list (see for example [3]), and it's already been narrowly applied for SCRAM's channel binding, since allowing a server to sidestep the client authentication defeats the purpose. But I'd like to see this applied generally, so that if the server sends an authentication request that my client hasn't been explicitly configured to use, the connection fails. Implementations could range from a simple "does the server's auth method match the single one I expect" to a full SASL mechanism negotation. WDYT? Are these worth pursuing in the near future? --Jacob [1] https://www.postgresql.org/about/news/postgresql-141-135-129-1114-1019-and-9624-released-2349/ [2] https://www.feistyduck.com/bulletproof-tls-newsletter/issue_80_vulnerabilities_show_fragility_of_starttls [3] https://www.postgresql.org/message-id/flat/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz%2BsKBXCQ%40mail.gmail.com