PyBitmessage-2021-04-27/src/class_objectHashHolder.py
Peter Surda 8f5d305242 Mitigate active internal intersection attack
There was a report that by quickly asking a large number of nodes if
they have an ACK object (which the attacker knows but it is injected
into the network by the recipient of the message), it can estimate how
an object propagates through the network, and eventually pinpoint an
originating IP address of the injection, i.e. the IP address of the
message recipient.

This patch mitigates against it by stalling when asked for a nonexisting
object (so that the attacker can't spam requests), and also upon
connection before sending its own inventory list (so that reconnecting
won't help the attacker). It estimates how long a short message takes to
propagate through the network based on how many nodes are in a stream
and bases the stalling time on that. Currently that is about 15 seconds.
Initial connection delay takes into account the time that already passed
since the connection was established.

This basically gives the attacker one shot per a combination of his own
nodes and the nodes he can connect to, and thus makes the attack much
more difficult to succeed.
2016-05-02 15:00:24 +02:00

47 lines
2.0 KiB
Python

# objectHashHolder is a timer-driven thread. One objectHashHolder thread is used
# by each sendDataThread. The sendDataThread uses it whenever it needs to
# advertise an object to peers in an inv message, or advertise a peer to other
# peers in an addr message. Instead of sending them out immediately, it must
# wait a random number of seconds for each connection so that different peers
# get different objects at different times. Thus an attacker who is
# connecting to many network nodes who receives a message first from Alice
# cannot be sure if Alice is the node who originated the message.
import random
import time
import threading
class objectHashHolder(threading.Thread):
size = 10
def __init__(self, sendDataThreadMailbox):
threading.Thread.__init__(self)
self.shutdown = False
self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread.
self.collectionOfHashLists = {}
self.collectionOfPeerLists = {}
for i in range(self.size):
self.collectionOfHashLists[i] = []
self.collectionOfPeerLists[i] = []
def run(self):
iterator = 0
while not self.shutdown:
if len(self.collectionOfHashLists[iterator]) > 0:
self.sendDataThreadMailbox.put((0, 'sendinv', self.collectionOfHashLists[iterator]))
self.collectionOfHashLists[iterator] = []
if len(self.collectionOfPeerLists[iterator]) > 0:
self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator]))
self.collectionOfPeerLists[iterator] = []
iterator += 1
iterator %= self.size
time.sleep(1)
def holdHash(self,hash):
self.collectionOfHashLists[random.randrange(0, self.size)].append(hash)
def holdPeer(self,peerDetails):
self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails)
def close(self):
self.shutdown = True