151 lines
No EOL
5.9 KiB
Text
151 lines
No EOL
5.9 KiB
Text
|
|
:experimental:
|
|
|
|
[[chap-Defensive_Coding-Authentication]]
|
|
=== Authentication and Authorization
|
|
|
|
[[sect-Defensive_Coding-Authentication-Server]]
|
|
==== 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 called
|
|
`PF_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.
|
|
|
|
[[sect-Defensive_Coding-Authentication-Host_based]]
|
|
==== 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.
|
|
|
|
[[sect-Defensive_Coding-Authentication-UNIX_Domain]]
|
|
==== 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.
|
|
|
|
[[sect-Defensive_Coding-Authentication-Netlink]]
|
|
==== `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. |