[Trying again without using the J word to beat the profanity filter. Really!?]
> 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. The thing that prevents one peer from impersonating another is each peer should have a unique secret shared only with the server. Any other client that attempts to send a message with a bogus client id will fail because it cannot authenticate the message (HMAC, etc) because it doesn't have the key. Client C sends message M to server S with key K using MC+HMAC(MC, K) -> S. This means the client sends the message M and client identity C along with the HMAC of the message M and client C using key K to the server S. Ok so far? Now, replay attacks are another problem. Client C sends message M to server S, and joshua J sees the message on the line. If J re-sends M to S, S cannot tell that the message didn't originate from C. I think this is the problem you're trying to explain. So what is one way to solve it? Time. When client C sends a message, we add time T to the message: MCT+HMAC(MCT, K) -> S Once the server receives the message, it verifies the HMAC of MCT to authenticate the message, then verifies the time T is within +/-whatever seconds of "now". If a time stamp on a message deviates more than however many seconds/minutes/whatever from the server time, we assume the message is a replay and discard it. Another method is an integer sequence I. For every message M the client sends, it increments the counter. I++, then MCI+HMAC(MCI, K) -> S The server maintains a dictionary D of counters by client C. We'll call this D[C] = I When the server S receives a message M from the client C, it can check D[C] <= I to see if the last seen counter is less than or equal to the received messages' I. If so, discard the message as a replay. If not, save D[C] = I for the next time we receive a message from the client. An advantage to using time is that you don't have to hold a dictionary on the server. However if a replay could happen in sub-millisecond time, you may not be able to reliably use that method. Hope this helps. On Sat, May 11, 2013 at 10:59 PM, Eric Hill <[email protected]> wrote: > > 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. > > The thing that prevents one peer from impersonating another is each peer > should have a unique secret shared only with the server. Any other client > that attempts to send a message with a bogus client id will fail because it > cannot authenticate the message (HMAC, etc) because it doesn't have the > key. Client C sends message M to server S with key K using MC+HMAC(MC, K) > -> S. This means the client sends the message M and client identity C > along with the HMAC of the message M and client C using key K to the server > S. Ok so far? > > Now, replay attacks are another problem. Client C sends message M to > server S, and jerk J sees the message on the line. If J re-sends M to S, S > cannot tell that the message didn't originate from C. I think this is the > problem you're trying to explain. > > So what is one way to solve it? Time. > > When client C sends a message, we add time T to the message: > MCT+HMAC(MCT, K) -> S > > Once the server receives the message, it verifies the HMAC of MCT to > authenticate the message, then verifies the time T is within +/-whatever > seconds of "now". If a time stamp on a message deviates more than however > many seconds/minutes/whatever from the server time, we assume the message > is a replay and discard it. > > Another method is an integer sequence I. For every message M the client > sends, it increments the counter. I++, then MCI+HMAC(MCI, K) -> S > > The server maintains a dictionary D of counters by client C. We'll call > this D[C] = I > > When the server S receives a message M from the client C, it can check > D[C] <= I to see if the last seen counter is less than or equal to the > received messages' I. If so, discard the message as a replay. If not, > save D[C] = I for the next time we receive a message from the client. > > An advantage to using time is that you don't have to hold a dictionary on > the server. However if a replay could happen in sub-millisecond time, you > may not be able to reliably use that method. > > Hope this helps. > > > > > On Sat, May 11, 2013 at 2:14 PM, Randall Nortman <[email protected]>wrote: > >> 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 >> > >
_______________________________________________ zeromq-dev mailing list [email protected] http://lists.zeromq.org/mailman/listinfo/zeromq-dev
