Can `listen_addresses` system configuration setting in Postgres stop pre-authentication exploits?
listen_addresses filters connections before postgres sees them


  ➥ Does this mean listen_addresses theoretically stops pre-authentication exploits?


Yes. If PostgreSQL's postmaster isn't listening on a given interface (as identified by its local address) then no remote host may connect to it via that interface. The operating system will report the TCP port as closed and send a TCP RST to the connecting host; PostgreSQL code is never reached, so PostgreSQL bugs cannot be exploited, even pre-auth ones.1.

listen_addresses blocks pre-auth exploits


  Is there any engagement between the Postgres server and the incoming connection which might possibly result in an exploit? Or will the forbidden incoming connection be blocked without any engagement?


No. listen_addresses configures the listening TCP socket at the operating system level, binding it only to the network interface(s) specified2. It filters on the connection target address specified by the remote host. The OS won't tell PostgreSQL about connections to other interfaces at all.

Note that the same is is not true of pg_hba.conf. pg_hba.conf controls remote-host source address filtering and authentication configuration. The PostgreSQL postmaster does handle any connection that comes in on a listened-on address and is then rejected by pg_hba.conf configuration.

You can do sender-address based filtering before PostgreSQL sees the connection by configuring operating system firewall rules. Those will prevent PostgreSQL pre-auth exploits by blocking the connection from ever reaching PostgreSQL.

So if you know that only the hosts in network 111.1.0.0/16 have any business connecting to your PostgreSQL it's a good idea to configure a firewall rule accordingly. You should set pg_hba.conf as a fallback, but the firewall rule should stop anyone even attempting to connect to postgres itself.

Understanding authentication flow

To connect to postgres you must pass a series of "gates" of sorts. Ignoring UNIX sockets for this explanation, we have:


OS network and TCP level, before you hit PostgreSQL code:


Any border router or firewall between you and postgres must permit the TCP connection
Any operating system firewall configured on the postgres host must permit the TCP connection
listen_addresses - postgres must be listening on the interface or the OS treats the TCP port as closed
Any network security extensions like TCP Wrappers (/etc/hosts.allow and /etc/hosts.deny) must permit the connection. (Assuming they're supported on your OS and postgres is compiled to use them)

Within PostgreSQL code:


A pg_hba.conf host, hostssl or hostnossl rule is found when matching by source-address, ssl mode, target dbname and requested username
The matched pg_hba.conf rule must not specify reject
If SSL client certificate checks are enabled, the SSL client certificate satisfies the configured CA cert.
The requested username and database name must both exist in the PostgreSQL catalogs
The requested username or a role it inherits must have the LOGIN option in the PostgreSQL catalogs
The requested user must have CONNECT rights to the requested database. (By default the public role all users are a member of has CONNECT rights, but you can REVOKE that and GRANT it only to specific users or roles/groups).

Yay, you've connected


If a connection is blocked at an earlier stage, it never interacts with later stages. I haven't checked the exact ordering of the dbname vs username privilege checks, but the rest is right.

I ignored pg_ident.conf and username mappings, client cert DN mappings, the details of things like SSPI/GSSAPI and low level auth methods, etc here.

Now, if you're using UNIX sockets (unix_socket_directories, and a libpq host address that's a path or omitted entirely), the PostgreSQL stage is the same except that pg_hba.conf matching doesn't check source-address and looks for local lines instead of host, hostssl or hostnossl lines. The peer auth mode is supported to require a unix username to postgres username match. Details in the manual.

Exposing PostgreSQL to the Internet

Let me note that pre-auth exploits for PostgreSQL are not wholly unheard of, but are rare. It's fairly routine to expose PostgreSQL on the Internet directly.

You should use hostssl in pg_hba.conf to enforce SSL connections to protect authentication exchanges and make casual scanning a bit harder. And you should adopt the same protective measures you use for any other Internet-exposed service: use fail2ban or similar, use an IDS, monitor logs, and have firewall rules to exclude anything that you know has no business connecting.

However, if you don't need to expose PostgreSQL to the Internet, don't do it. In particular, if you only need loopback connections, bind PostgreSQL to the loopback address(es) 127.0.0.1 and ::1. Or even better, use unix sockets.

See also


The "Client Authentication" chapter of the manual
listen_addresses
pg_hba.conf
For Ubuntu and (mostly) Debian:


Ubuntu docs for Ubuntu's PostgreSQL packages
Ubuntu community help wiki for PostgreSQL





1 The attacker could still exploit OS bugs in the network stack. Or (very unlikely) they might be able to use tricks like source-address spoofing to fool a buggy OS into letting it send an initial packet to PostgreSQL even when it's bound to a different interface. Any modern, sensibly configured OS will prevent that.

2 Internally each listen_addresses entry is used to make a separate listening TCP socket. For UNIX-like OSes it's passed to the bind(...) call on each socket. See postmaster.c around line 1012, if (ListenAddresses), and see the StreamServerPort adapter in src/backend/libpq/pqcomm.c around line 532.