You can set various configuration parameters for Postgres by either editing the postgresql.conf
file manually or by calling ALTER SYSTEM
commands.
One of those config settings is listen_addresses
. To quote the documentation:
Specifies the TCP/IP address(es) on which the server is to listen for connections from client applications. The value takes the form of a comma-separated list of host names and/or numeric IP addresses. The special entry * corresponds to all available IP interfaces. The entry 0.0.0.0 allows listening for all IPv4 addresses and :: allows listening for all IPv6 addresses. If the list is empty, the server does not listen on any IP interface at all, in which case only Unix-domain sockets can be used to connect to it. The default value is localhost, which allows only local TCP/IP “loopback” connections to be made. While client authentication (Chapter 20) allows fine-grained control over who can access the server, listen_addresses controls which interfaces accept connection attempts, which can help prevent repeated malicious connection requests on insecure network interfaces. This parameter can only be set at server start.
➥ Does this mean listen_addresses
theoretically stops pre-authentication 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?
Of course, ideally, a firewall on the host operating system would also be in place to block unwanted incoming connections. But let’s ignore firewalls for the purpose of this Question.
Best Answer
listen_addresses
filters connections before postgres sees themYes. 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 exploitsNo.
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 bypg_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:
listen_addresses
- postgres must be listening on the interface or the OS treats the TCP port as closed/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)pg_hba.conf
host
,hostssl
orhostnossl
rule is found when matching by source-address, ssl mode, target dbname and requested usernamepg_hba.conf
rule must not specifyreject
LOGIN
option in the PostgreSQL catalogsCONNECT
rights to the requested database. (By default thepublic
role all users are a member of hasCONNECT
rights, but you canREVOKE
that andGRANT
it only to specific users or roles/groups).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 alibpq
host
address that's a path or omitted entirely), the PostgreSQL stage is the same except thatpg_hba.conf
matching doesn't check source-address and looks forlocal
lines instead ofhost
,hostssl
orhostnossl
lines. Thepeer
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
inpg_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
listen_addresses
pg_hba.conf
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 thebind(...)
call on each socket. Seepostmaster.c
around line 1012,if (ListenAddresses)
, and see theStreamServerPort
adapter insrc/backend/libpq/pqcomm.c
around line 532.