mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Finish edits to repository tool doc and update code to fix issues with slow retrieval errors
This commit is contained in:
parent
404398a0b6
commit
07b4b24343
3 changed files with 35 additions and 16 deletions
|
|
@ -891,25 +891,31 @@ Error: No working mirror was found:
|
|||
### Slow Retrieval Attack ###
|
||||
In a slow retrieval attack, an attacker responds to clients with a very slow
|
||||
stream of data that essentially results in the client never continuing the
|
||||
update process. For this example, we simulate a slow retrieval attack by
|
||||
spawning a server that serves our update client data at a slow rate. TUF
|
||||
should not be vulnerable to this attack, and the framework should raise an
|
||||
update process. In this example, we simulate a slow retrieval attack by
|
||||
spawning a server that serves data at a slow rate to our update client data.
|
||||
TUF should not be vulnerable to this attack, and the framework should raise an
|
||||
exception or error when it detects that a malicious server is serving it data
|
||||
at a slow enough rate.
|
||||
|
||||
We first spawn a server that slowly streams data to a client request. The
|
||||
'slow_retrieval_server.py' module can be copied over to the '../demo_repository'
|
||||
directory from which to launch it.
|
||||
We first spawn the server that slowly streams data to the client. The
|
||||
'slow_retrieval_server.py' module (can be found in the tests/ directory of the
|
||||
source code) should be copied over to the server's 'repository/' directory from
|
||||
which to launch it.
|
||||
|
||||
```Bash
|
||||
# Before launching the slow retrieval server, copy 'slow_retrieval_server.py'
|
||||
# to the 'repository/' directory and run it from that directory. Assuming
|
||||
# the current working directory is "repository/":
|
||||
$ cp ../../../tests/slow_retrieval_server.py .
|
||||
$ python slow_retrieval_server.py 8002 mode_2
|
||||
```
|
||||
|
||||
The client may now make a request to the slow server on port 8002. However,
|
||||
before doing so, we'll need to reduce (for the purposes of this demo) the
|
||||
minimum average download rate allowed. Open the '.../demo/tuf/tuf/conf.py'
|
||||
file and set MIN_AVERAGE_DOWNLOAD_SPEED to 1. This should make it so
|
||||
that client correctly detects the slow retrieval server's delayed streaming.
|
||||
The client may now make a request to the slow retrieval server on port 8002.
|
||||
However, before doing so, we'll reduce (for the purposes of this demo) the
|
||||
minimum average download rate allowed and download chunk size. Open the
|
||||
'conf.py' module and set MIN_AVERAGE_DOWNLOAD_SPEED = 5 and CHUNK_SIZE = 1.
|
||||
This should make it so that the client detects the slow retrieval server's
|
||||
delayed streaming.
|
||||
|
||||
```Bash
|
||||
$ python basic_client.py --verbose 1 --repo http://localhost:8002
|
||||
|
|
@ -917,8 +923,8 @@ Error: No working mirror was found:
|
|||
u'localhost:8002': SlowRetrievalError()
|
||||
```
|
||||
|
||||
The framework should detect the attack and raise a SlowRetrievalError
|
||||
exception to the client application.
|
||||
The framework should detect the slow retrieval attack and raise a
|
||||
SlowRetrievalError exception to the client application.
|
||||
|
||||
|
||||
## Conclusion ##
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ def __init__(self, average_download_speed):
|
|||
self.__average_download_speed = average_download_speed #bytes/second
|
||||
|
||||
def __str__(self):
|
||||
return 'Download was too slow. The average download speed has gone' +\
|
||||
return 'Download was too slow. The average download speed dropped' +\
|
||||
' below the minimum download speed of ' +\
|
||||
repr(self.__average_download_speed) + ' bytes per second.'
|
||||
|
||||
|
|
|
|||
|
|
@ -330,14 +330,14 @@ def _download_fixed_amount_of_data(connection, temp_file, required_length):
|
|||
data = b''
|
||||
read_amount = min(tuf.conf.CHUNK_SIZE,
|
||||
required_length - number_of_bytes_received)
|
||||
|
||||
|
||||
try:
|
||||
data = connection.read(read_amount)
|
||||
|
||||
# Python 3.2 returns 'IOError' if the remote file object has timed out.
|
||||
except (socket.error, IOError):
|
||||
pass
|
||||
|
||||
|
||||
number_of_bytes_received = number_of_bytes_received + len(data)
|
||||
|
||||
# Data successfully read from the connection. Store it.
|
||||
|
|
@ -356,7 +356,13 @@ def _download_fixed_amount_of_data(connection, temp_file, required_length):
|
|||
average_download_speed = number_of_bytes_received / seconds_spent_receiving
|
||||
|
||||
if average_download_speed < tuf.conf.MIN_AVERAGE_DOWNLOAD_SPEED:
|
||||
logger.debug('The average download speed dropped below the minimum'
|
||||
' average download speed set in conf.py.')
|
||||
break
|
||||
|
||||
else:
|
||||
logger.debug('The average download speed has not dipped below the'
|
||||
' mimimum average download speed set in conf.py.')
|
||||
|
||||
# We might have no more data to read. Check number of bytes downloaded.
|
||||
if not data:
|
||||
|
|
@ -641,6 +647,13 @@ def _check_downloaded_length(total_downloaded, required_length,
|
|||
# will log a warning anyway. This is useful when we wish to download the
|
||||
# Timestamp or Root metadata, for which we have no signed metadata; so,
|
||||
# we must guess a reasonable required_length for it.
|
||||
if average_download_speed < tuf.conf.MIN_AVERAGE_DOWNLOAD_SPEED:
|
||||
raise tuf.SlowRetrievalError(average_download_speed)
|
||||
|
||||
else:
|
||||
logger.debug('Good average download speed: ' +
|
||||
repr(average_download_speed) + ' bytes per second')
|
||||
|
||||
logger.info('Downloaded ' + str(total_downloaded) + ' bytes out of an'
|
||||
' upper limit of ' + str(required_length) + ' bytes.')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue