]
RH Bugzilla Integration commented on JGRP-2021:
-----------------------------------------------
Pavel Polischouk <pavelp(a)redhat.com> changed the Status of [bug
ENCRYPT: prevent messages from non-members
------------------------------------------
Key: JGRP-2021
URL:
https://issues.jboss.org/browse/JGRP-2021
Project: JGroups
Issue Type: Feature Request
Reporter: Bela Ban
Assignee: Bela Ban
Fix For: 4.0
Although JGroups provides message encryption ({{ENCRYPT}}) and cluster admission control
({{AUTH}}), it _does not_ prevent malicious attacks.
For example, if a rogue node creates a minimal stack without encryption or
authentication, then it is possible for that member to
* Send messages to the cluster
* Capture an existing message from a cluster member P, change it (e.g. the seqno) and
resend it spooking P's address
* Install a new view including itself
* Possibly install a new shared key in {{ENCRYPT}}, thereby being able to _receive_
cluster messages
h3. Goals
1. Prevent cluster members from delivering messages from a non-member (exceptions are
join requests from new members and merge requests)
2. Prevent a non-member from receiving any cluster messages
The first goal also prevents rogue views from getting installed, or new shared secrets
from being installed into {{ENCRYPT}}.
h3. Proposed solution
* Use ENCRYPT for encryption of the payload *and the headers*
* Now _every message_ carries an encrypt header
* (Let's assume for the moment that {{ENCRYPT}} is configured to use a shared key)
* When a message is received, it is decrypted using the shared key (this can only be done
by members having the shared key)
** If the message doesn't have an encrypt header, it will be dropped
* For some messages that carry their information in the payload rather than the headers,
we don't even need to encrypt the entire message (which is faster), e.g.
** Views and MergeViews: they are stored in the payload ({{GMS}})
** A new secret key sent by the key server is also stored in the payload ({{ENCRYPT}})
* ALTERNATIVE I:
** We encrypt a phrase with the secret key. Everyone who has the shared key will be able
to decrypt it and thus pass a message up. Messages from a non-member would be dropped.
** Could the above also be done by the sender _signing_ a phrase with its private key and
the receiver decrypting it with the sender's public key, to enforce non-repudiation?
** Hmm, this would be prone to replay attacks, so either the phrase would have to be
changed every time, or the ENCRYT header would have to be encrypted as well
({{encrypt_entire_msg==true}}.
* ALTERNATIVE II: digital signature
** The sender creates a hash from the message (digest) and encrypts the digest with its
secret key, and ships it with the message
** The receiver decrypts the digest, computes the digest from the message and drops the
message if the digests don't match
** The diff to the first alternative is that a receiver doesn't even need to deliver
the message and stop at (failing) de-serialization.
** Downside: additional work to be done and space used when sending the signature with
every message
h3. Scenarios to test (ENCRYPTTest)
h5. Catching a message from some member P, modifying it and re-sending it on behalf of P
* A rogue member R could catch a message from P by simply joining the same multicast
group and port
* R could then increment the last seqno seen, e.g. 23, to 24 and send the message on
behalf of P
* However, the decryption won't work because R doesn't have the shared key. Also,
modifying the headers and resending the message won't work as R cannot get at the
headers because they're encrypted, too
* R could still resend the _captured message_ but that's useless as (a) one of the
retransmission protocols (UNICAST3 or NAKACK2) will drop the duplicate message
h5. Installing a rogue view
* This requires {{ENCRYPT}} to sit somewhere below {{GMS}}
* R sends a new view consisting of the existing view plus R
* If ENCRYPT passes the message up because it doesn't discard message without encrypt
header, GMS will install the new view!
h5. The rogue node installing a new secret key in all members (ENCRYPT)
* R sends a {{SECRETKEY}} msg with a new shared key, encrypted with its public key
* Everyone install the new shared secret and R can now receive encrypted messages from
cluster members!
h5. Non-member R sending a message encrypted with its own secret key
* Cluster members would receive that message and decrypt it with their own (different)
shared key, leading to garbage in the payload
* The message would get delivered to the application but de-serialization would fail as
the payload is garbage
** See ALTERNATIVE above to prevent cluster members from delivering messages from rogue
members in the first place
h4. Properties
* Rogue non-member R
* Resending of captures (and unmodified) cluster messages by R: YES (however, those
messages will get dropped by either {{NAKACK2}} or {{UNICAST3}} as duplicates)
* Capturing and resending of messages as _new messages_ by R (e.g. by incrementing the
seqno): YES if {{ENCRYPT.encrypt_entire_msg}} is false, NO if true
* Reception of cluster messages by R: YES, but R won't be able to read the contents
as the payload is encrypted
* Cluster members receiving messages from R: YES, but applications will throw an
exception trying to read the contents of the payload as it is encrypted, and decryption
failed as the secret key was wrong.
h4. Issues
* How do we handle (unicast) JOINs from non-members?
* Ditto for merge requests (unicasts)