Prevent same-list replays
over on #158 (closed), we discussed cross-list replay attacks, which are resolved by requiring x-listname:
headers.
however, x-listname:
doesn't mitigate same-list replay attacks for control messages.
There are several possible mitigations, most of them having to do with some sort of stored state anti-replay protections, which may or may not introduce more problems than they solve ;)
Here are three suggestions, along with some caveats:
Last Received
- for each admin for a given list, keep track of the OpenPGP timestamp of the signature of the last-received message from that admin as
last_received
. - when a new message comes in for that list from that admin, verify that the signature is later than the associated
last_received
.
This has a few potential traps lurking in it:
- what if the admin is on a machine with a shifting clock? can they lock out their future messages if they accidentally send one message from the year 3000?
- what if messages get delayed and re-ordered in transit?
All Received
- for each admin for a given list, keep track of all signatures ever seen by that admin as a list
known_signatures
(you can get aSIG_ID
from the GnuPG status lines which should be globally unique) - when a new signed, verified message comes in from that admin for that list, compare the signature with the
known_signatures
. If it's already been seen, reject the message.
caveats:
- this appears to grow without bound, which is problematic in (at least) two ways:
- a malicious list admin could stuff the server full of records to cause it to overflow
- it creates a log of who interacts with the server and when, which is a chunk of metadata that the list operators might not want to be liable for.
Recently Received
We can synthesize the two above with a bit more complexity, and with some baseline assumptions/requirements about system clocks. Pick two time allowances, F
("forward skew") and B
("backward skew"). (consider F=B=1 week
for now)
- When a message comes in at server time
T
for a given admin on a given list, and that message signature has timeS
, reject the message ifS < T-B
orS > T+F
- if the message is not rejected due to time, compare it's signature ID with
known_signatures
for that admin for that list. - if it is already present, reject the message
- if it is not present, store
<SIG_ID,S>
inknown_signatures
and process the message - during regular maintenance at server time
X
(cronjob? scheduled timer?), delete all entries inknown_signatures
whereS < X-B
caveats:
- this is more complex to implement than the other proposals, and has more types of errors/message rejections
- you have to choose
F
andB
-- more knobs to twiddle, yuck. ProbablyB
should be greater than the maximum expected SMTP delay time (4 days), but not too much longer (to minimize data retention).F
needs to be set to accomodate clock skew seen in the wild, which i don't have data on. - what happens if the clock on the server itself is wacky? Does schleuder need to depend on having a mostly-correct system clock?