Repository: freedomofpress/securedrop

Issue:
Reduce time information leakage of file uploads and file downloads
Current implementation of the file upload handler seems to be subject of time information leakage in relation to the zip implementation used in order to optimize the download time.

As the file is uploaded, the file is read as SecureTemporaryFile and wrapped in a GZIP to offer an offline single compression mechanism of the file and reduce further download overhead; During the gzip process the local time (as approximation of the time of the effective file upload) seems to be included in the archive.

The described issue affects `save_file_submission` in store.py https://github.com/freedomofpress/securedrop/blob/670c8baf18f84b15c0481f82c11e06cfc97da28f/securedrop/store.py#L133-L134

Proposed solutions for this is the use of the `mtime` that could be passed to `gzip.GzipFile` setting a fake date.
A reasonable easy approach, easy understandable by end users, could probably be to set the date to the the Unix epoch (0:00:00 UTC of 1 January 1970)

Similar conditions seems to affect the download `get_bulk_archive`:
https://github.com/freedomofpress/securedrop/blob/670c8baf18f84b15c0481f82c11e06cfc97da28f/securedrop/store.py#L89

When a Journalist download a bulk archive the stored gzip files are wrapped in a new gzipped file that will include:
- the internal timestamp saved inside the gzip file (as part of each included file);
- the local timestamp of the gzip file saved on the disk (as metadata for each single gzip file included in the gzip archive);
- the local time of the download is attached to the zip file disclosing in the zip file the time of the server as the time of the download. (inside the header of the wrapping gzip archive, eventually leaking the timezone of the server).

Solution for this second problem is more difficult because the ```ZipFile``` implementation requires to be patched.
In GlobaLeaks this issue is addressed by including a modified version of the spideroak zipstream implementation: https://github.com/globaleaks/GlobaLeaks/blob/0acf994b1a7e64cbaf35d950f6c76cc5c22ac7b9/backend/globaleaks/utils/zipstream.py

Inclusion of such a streaming implementation offers the additional value of  solving a possible DoS vector when a big amount of files zipped at once.

The issues here described probably affects the solution of ticket https://github.com/freedomofpress/securedrop/issues/301 where an implementation based on  `touch`  was considering to change the timestamp of previously uploaded files at the arrival of a new file. Due to the reported bug on the Gzip implementation, the compressed archive will continue to maintain internally the original timestamp.


Discussion:

Resolving patch:
diff --git a/securedrop/store.py b/securedrop/store.py
--- a/securedrop/store.py
+++ b/securedrop/store.py
@@ -131,7 +131,7 @@ def save_file_submission(self, filesystem_id, count, journalist_filename,
         encrypted_file_path = self.path(filesystem_id, encrypted_file_name)
         with SecureTemporaryFile("/tmp") as stf:  # nosec
             with gzip.GzipFile(filename=sanitized_filename,
-                               mode='wb', fileobj=stf) as gzf:
+                               mode='wb', fileobj=stf, mtime=0) as gzf:
                 # Buffer the stream into the gzip file to avoid excessive
                 # memory consumption
                 while True:


Test patch:
diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py
--- a/securedrop/tests/test_source.py
+++ b/securedrop/tests/test_source.py
@@ -428,7 +428,8 @@ def test_submit_sanitizes_filename(source_app):
             assert resp.status_code == 200
             gzipfile.assert_called_with(filename=sanitized_filename,
                                         mode=ANY,
-                                        fileobj=ANY)
+                                        fileobj=ANY,
+                                        mtime=0)
 
 
 def test_tor2web_warning_headers(source_app):