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 10.0.0.96, 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? _______________________________________________ zeromq-dev mailing list [email protected] http://lists.zeromq.org/mailman/listinfo/zeromq-dev
