[zeromq-dev] Message source identification/authentication

Randall Nortman rnzmq at wonderclown.net
Sat May 11 21:14:03 CEST 2013

I know this has been discussed before on this list and there are some
RFC's related to secure authentication, but I have not yet seen any
reasonable solutions, because of a limitation in the libzmq API.  The
encryption/authentication built into ZMTPv3.0 doesn't seem to fix the
problem, because the problem is at the API level.  Let me start by
illustrating the problem with a simple example:

Let's say we have a server which maintains some data for
clients/peers.  Let's call the data "files" for this example, but it
could be anything.  The files are owned by particular clients (which
are peers with respect to the protocol, but clients with respect to
the file service).  Clients are somehow known to the server
(previously shared keys), and they can store and retrieve their own
files, but should not be able to access the files of other clients.

Let's say you do something smart like put the whole thing on a VPN
using client certificates to authenticate clients and assign them a
static IP on the VPN.  The VPN makes sure that the private IP
addresses cannot be spoofed.  So if I were writing a server based on
traditional sockets rather than ZMQ, I'd just trust that if I get a
packet from, then that is definitely from the client
assigned that address and no additional authentication is required.
You could also do it with SSL using client certificates, and then my
SSL-based server would just query the SSL library for the identity of
the client connected to the socket and everything would be great.

Now let's say you've got ZMQ running on top of the same kind of VPN or
SSL setup.  Or you're using the CurveCP/CurveZMQ underlying transport
or the SASL mechanism in the ZMTPv3.0 spec.  Great, you at least know
that anybody that connects to you is a known peer.  But when you get a
message, you don't know what peer sent it, because zmq_recv has no way
of communicating that to you.  So your protocol of course will need to
have the client ID in each message.  But what prevents one peer from
impersonating another?  Absolutely nothing, because by the time the
message gets to the application layer the authentication information
has been lost.

So now you *have* to put authentication on top of ZMQ, at the
application level, and sign each message.  So now each ZMQ application
needs to implement crypto, and it is way, way too easy to get that
wrong to have it happening at the application layer.  (The
pubsub-security draft at http://www.zeromq.org/topics:pubsub-security
nicely illustrates how easy it is to get this stuff terribly, horribly
wrong, because nothing in that protocol stops replay attacks, as has
already been pointed out in the comments.)

Furthermore, it seems like unnecessary overhead, given that the
underlying layers may already have authenticated the peer (if auth at
the ZMTP layer is being used, for example, or CurveCP/TLS/VPN
underneath that).

Could the API simply provide a way to identify the sender of each
message somehow?  The "identity" could be handled as a blob whose
interpretation is dependent on the underlying transport, anything from
an IP address up to the CN from the peer's X509 certificate.  This
does not do a whole lot to help in the case of multi-hop
(routed/proxied) messages, but it at least gives you single-hop
authentication, which is good enough for a large number of
applications.  And it could perhaps serve as the basis for end-to-end
multi-hop authentication as well.  If end-to-end auth is going to be
done by signing each message (a reasonable way to do it), then that
*must* be part of the ZMQ spec and the libzmq implementation, because
you simply cannot leave it up to each application to design and
implement crypto properly.

Am I missing something?  Has this been handled somehow already?

More information about the zeromq-dev mailing list