Authentication and Authorization
Authenticating Servers
When connecting to a server, a client has to make sure that it is actually talking to the server it expects. There are two different aspects, securing the network path, and making sure that the expected user runs the process on the target host. There are several ways to ensure that:
-
The server uses a TLS certificate which is valid according to the web browser public key infrastructure, and the client verifies the certificate and the host name.
-
The server uses a TLS certificate which is expected by the client (perhaps it is stored in a configuration file read by the client). In this case, no host name checking is required.
-
On Linux, UNIX domain sockets (of the
PF_UNIX
protocol family, sometimes calledPF_LOCAL
) are restricted by file system permissions. If the server socket path is not world-writable, the server identity cannot be spoofed by local users. -
Port numbers less than 1024 (trusted ports) can only be used by
root
, so if a UDP or TCP server is running on the local host and it uses a trusted port, its identity is assured. (Not all operating systems enforce the trusted ports concept, and the network might not be trusted, so it is only useful on the local system.)
TLS ([chap-Defensive_Coding-TLS]) is the recommended way for securing connections over untrusted networks.
If the server port number is 1024 is higher, a local user can impersonate the process by binding to this socket, perhaps after crashing the real server by exploiting a denial-of-service vulnerability.
Host-based Authentication
Host-based authentication uses access control lists (ACLs) to
accept or deny requests from clients. This authentication
method comes in two flavors: IP-based (or, more generally,
address-based) and name-based (with the name coming from DNS or
/etc/hosts
). IP-based ACLs often use
prefix notation to extend access to entire subnets. Name-based
ACLs sometimes use wildcards for adding groups of hosts (from
entire DNS subtrees). (In the SSH context, host-based
authentication means something completely different and is not
covered in this section.)
Host-based authentication trust the network and may not offer sufficient granularity, so it has to be considered a weak form of authentication. On the other hand, IP-based authentication can be made extremely robust and can be applied very early in input processing, so it offers an opportunity for significantly reducing the number of potential attackers for many services.
The names returned by gethostbyaddr
and
getnameinfo
functions cannot be trusted.
(DNS PTR records can be set to arbitrary values, not just names
belong to the address owner.) If these names are used for ACL
matching, a forward lookup using
gethostbyaddr
or
getaddrinfo
has to be performed. The name
is only valid if the original address is found among the results
of the forward lookup (double-reverse
lookup).
An empty ACL should deny all access (deny-by-default). If empty ACLs permits all access, configuring any access list must switch to deny-by-default for all unconfigured protocols, in both name-based and address-based variants.
Similarly, if an address or name is not matched by the list, it should be denied. However, many implementations behave differently, so the actual behavior must be documented properly.
IPv6 addresses can embed IPv4 addresses. There is no universally correct way to deal with this ambiguity. The behavior of the ACL implementation should be documented.
UNIX Domain Socket Authentication
UNIX domain sockets (with address family
AF_UNIX
or AF_LOCAL
) are
restricted to the local host and offer a special authentication
mechanism: credentials passing.
Nowadays, most systems support the
SO_PEERCRED
(Linux) or
LOCAL_PEERCRED
(FreeBSD) socket options, or
the getpeereid
(other BSDs, OS X).
These interfaces provide direct access to the (effective) user
ID on the other end of a domain socket connect, without
cooperation from the other end.
Historically, credentials passing was implemented using
ancillary data in the sendmsg
and
recvmsg
functions. On some systems, only
credentials data that the peer has explicitly sent can be
received, and the kernel checks the data for correctness on the
sending side. This means that both peers need to deal with
ancillary data. Compared to that, the modern interfaces are
easier to use. Both sets of interfaces vary considerably among
UNIX-like systems, unfortunately.
If you want to authenticate based on supplementary groups, you
should obtain the user ID using one of these methods, and look
up the list of supplementary groups using
getpwuid
(or
getpwuid_r
) and
getgrouplist
. Using the PID and
information from /proc/PID/status
is prone
to race conditions and insecure.
AF_NETLINK
Authentication of Origin
Netlink messages are used as a high-performance data transfer mechanism between the kernel and the user space. Traditionally, they are used to exchange information related to the network stack, such as routing table entries.
When processing Netlink messages from the kernel, it is
important to check that these messages actually originate from
the kernel, by checking that the port ID (or PID) field
nl_pid
in the sockaddr_nl
structure is 0
. (This structure can be
obtained using recvfrom
or
recvmsg
, it is different from the
nlmsghdr
structure.) The kernel does not
prevent other processes from sending unicast Netlink messages,
but the nl_pid
field in the sender’s socket
address will be non-zero in such cases.
Applications should not use AF_NETLINK
sockets as an IPC mechanism among processes, but prefer UNIX
domain sockets for this tasks.