[zeromq-dev] Message source identification/authentication
Eric Hill
eric at ijack.net
Sun May 12 06:02:08 CEST 2013
[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 <eric at ijack.net> 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 <rnzmq at wonderclown.net>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
>> zeromq-dev at lists.zeromq.org
>> http://lists.zeromq.org/mailman/listinfo/zeromq-dev
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.zeromq.org/pipermail/zeromq-dev/attachments/20130511/7c886d57/attachment.htm>
More information about the zeromq-dev
mailing list