uploadserver 6.0.2__tar.gz → 6.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uploadserver
3
- Version: 6.0.2
3
+ Version: 6.0.4
4
4
  Summary: Python's http.server extended to include a file upload page
5
5
  Home-page: https://github.com/Densaugeo/uploadserver
6
6
  Author: Densaugeo
@@ -203,6 +203,11 @@ options:
203
203
  - File field in upload form renamed from `file_1` to `files`, to reflect support for multiple file upload. Scripts using cURL will need to be upadted with the new field name.
204
204
  - Successful uploads now respond with 204 No Content instead of 200 OK, so that cURL will not default to printing the upload page at the terminal.
205
205
 
206
+ ## Security Issues
207
+
208
+ - Patched in `6.0.3`: Timing side channel. Introduced in `1.0.0`. Unpatched versions using the `--basic-auth`, `--basic-auth-upload`, or `--token` options are vulnerable to revealing password information through response timing.
209
+ - Patched in `6.0.2`: DoS vulnerability. Introduced in `4.1.0`. Unpatched versions using the `--basic-auth` or `--basic-auth-upload` options generate stack traces in response to certain requests, which could be used to pollute logs or exhaust storage.
210
+
206
211
  ## Acknowledgements
207
212
 
208
213
  Much of `main()` was copied from Python's `http.server`.
@@ -217,4 +222,6 @@ Thanks to shuangye for finding an easy way to handle large file uploads, and imp
217
222
 
218
223
  Thanks to abbbe for adding HTTP basic auth (has now replaced the token option).
219
224
 
220
- Thanks to SimarMugattarov, theo543, and poshul for minor updates.
225
+ Thanks to 0xLordMahesh for reporting the timing side channel and DoS vulnerabilities patched in 6.0.2 and 6.0.3.
226
+
227
+ Thanks to SimarMugattarov, theo543, poshul, and OnkarRuikar for minor updates.
@@ -180,6 +180,11 @@ options:
180
180
  - File field in upload form renamed from `file_1` to `files`, to reflect support for multiple file upload. Scripts using cURL will need to be upadted with the new field name.
181
181
  - Successful uploads now respond with 204 No Content instead of 200 OK, so that cURL will not default to printing the upload page at the terminal.
182
182
 
183
+ ## Security Issues
184
+
185
+ - Patched in `6.0.3`: Timing side channel. Introduced in `1.0.0`. Unpatched versions using the `--basic-auth`, `--basic-auth-upload`, or `--token` options are vulnerable to revealing password information through response timing.
186
+ - Patched in `6.0.2`: DoS vulnerability. Introduced in `4.1.0`. Unpatched versions using the `--basic-auth` or `--basic-auth-upload` options generate stack traces in response to certain requests, which could be used to pollute logs or exhaust storage.
187
+
183
188
  ## Acknowledgements
184
189
 
185
190
  Much of `main()` was copied from Python's `http.server`.
@@ -194,4 +199,6 @@ Thanks to shuangye for finding an easy way to handle large file uploads, and imp
194
199
 
195
200
  Thanks to abbbe for adding HTTP basic auth (has now replaced the token option).
196
201
 
197
- Thanks to SimarMugattarov, theo543, and poshul for minor updates.
202
+ Thanks to 0xLordMahesh for reporting the timing side channel and DoS vulnerabilities patched in 6.0.2 and 6.0.3.
203
+
204
+ Thanks to SimarMugattarov, theo543, poshul, and OnkarRuikar for minor updates.
@@ -5,7 +5,7 @@ with open('README.md', 'r') as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name='uploadserver',
8
- version='6.0.2',
8
+ version='6.0.4',
9
9
  author='Densaugeo',
10
10
  author_email='author@example.com',
11
11
  description='Python\'s http.server extended to include a file upload page',
@@ -1,5 +1,5 @@
1
1
  import http.server, http, pathlib, sys, argparse, ssl, os, builtins, tempfile
2
- import ipaddress
2
+ import ipaddress, hmac
3
3
  import base64, binascii, functools, contextlib
4
4
 
5
5
  # Does not seem to do be used, but leaving this import out causes uploadserver
@@ -29,6 +29,9 @@ def get_upload_page(theme: str) -> bytes:
29
29
  </head>
30
30
  <body>
31
31
  <h1>File Upload</h1>
32
+ <hr />
33
+ <a href="/">File Download</a> (back to download page)
34
+ <hr />
32
35
  <form action="upload" method="POST" enctype="multipart/form-data">
33
36
  <input name="files" type="file" multiple />
34
37
  <br />
@@ -37,6 +40,7 @@ def get_upload_page(theme: str) -> bytes:
37
40
  </form>
38
41
  <p id="task"></p>
39
42
  <p id="status"></p>
43
+ <hr />
40
44
  </body>
41
45
  <script>
42
46
  document.getElementsByTagName('form')[0].addEventListener('submit', async e => {
@@ -83,7 +87,7 @@ def get_directory_head_injection(theme: str) -> bytes:
83
87
  ''', 'utf-8')
84
88
 
85
89
  DIRECTORY_BODY_INJECTION = b'''<!-- Injected by uploadserver -->
86
- <a href="/upload">File upload</a>
90
+ <a href="/upload">File Upload</a>
87
91
  (provided by uploadserver, all files go to server root)
88
92
  <hr>
89
93
  <!-- End injection by uploadserver -->
@@ -168,7 +172,7 @@ def receive_upload(handler: http.server.BaseHTTPRequestHandler,
168
172
 
169
173
  # True return type is tuple[bool, str | None], but Python 3.9 doesn't support |
170
174
  def check_http_authentication_header(
171
- handler: http.server.BaseHTTPRequestHandler, auth: str,
175
+ handler: http.server.BaseHTTPRequestHandler, auth: tuple[bytes, bytes],
172
176
  ) -> tuple[bool, str]:
173
177
  auth_header = handler.headers.get('Authorization')
174
178
  if auth_header is None:
@@ -187,9 +191,11 @@ handler: http.server.BaseHTTPRequestHandler, auth: str,
187
191
  return (False, 'Credentials incorrectly formatted')
188
192
 
189
193
  http_username, http_password = http_username_password.split(':', 1)
190
- args_username, args_password = auth.split(':', 1)
191
- if http_username != args_username: return (False, 'Bad username')
192
- if http_password != args_password: return (False, 'Bad password')
194
+ args_username, args_password = auth
195
+ if not hmac.compare_digest(bytes(http_username, 'utf8'), args_username):
196
+ return (False, 'Bad username')
197
+ if not hmac.compare_digest(bytes(http_password, 'utf8'), args_password):
198
+ return (False, 'Bad password')
193
199
 
194
200
  return (True, None)
195
201
 
@@ -206,12 +212,12 @@ def check_http_authentication(handler: http.server.BaseHTTPRequestHandler
206
212
  return True
207
213
 
208
214
  # If only --basic-auth is supplied, it's used for all requests
209
- valid, message = check_http_authentication_header(handler, args.basic_auth)
215
+ valid, message = check_http_authentication_header(handler, basic_auth)
210
216
  else:
211
217
  # If --basic-auth-upload is supplied, it's always required for /upload
212
218
  if handler.path == '/upload':
213
219
  valid, message = check_http_authentication_header(handler,
214
- args.basic_auth_upload)
220
+ basic_auth_upload)
215
221
  else:
216
222
  # For paths outside /upload, no auth is required when --basic-auth
217
223
  # is not supplied
@@ -221,10 +227,12 @@ def check_http_authentication(handler: http.server.BaseHTTPRequestHandler
221
227
  # For paths outise /upload, if both auths are supplied both are
222
228
  # accepted
223
229
  else:
224
- valid, message = check_http_authentication_header(handler, args.basic_auth)
230
+ valid, message = check_http_authentication_header(handler,
231
+ basic_auth)
225
232
 
226
233
  if not valid:
227
- valid, message = check_http_authentication_header(handler, args.basic_auth_upload)
234
+ valid, message = check_http_authentication_header(handler,
235
+ basic_auth_upload)
228
236
 
229
237
  if not valid:
230
238
  handler.log_message('Request rejected (%s)', message)
@@ -422,7 +430,7 @@ def serve_forever():
422
430
  )
423
431
 
424
432
  def main():
425
- global args
433
+ global args, basic_auth, basic_auth_upload
426
434
 
427
435
  parser = argparse.ArgumentParser()
428
436
  parser.add_argument('port', type=int, default=8000, nargs='?',
@@ -463,4 +471,13 @@ def main():
463
471
  'argument.'
464
472
  )
465
473
 
474
+ # Cache bytes() conversions of auth values, to prevent leaking information
475
+ # via timing (issue #53)
476
+ if args.basic_auth:
477
+ username, password = args.basic_auth.split(':', 1)
478
+ basic_auth = (bytes(username, 'utf8'), bytes(password, 'utf8'))
479
+ if args.basic_auth_upload:
480
+ username, password = args.basic_auth_upload.split(':', 1)
481
+ basic_auth_upload = (bytes(username, 'utf8'), bytes(password, 'utf8'))
482
+
466
483
  serve_forever()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uploadserver
3
- Version: 6.0.2
3
+ Version: 6.0.4
4
4
  Summary: Python's http.server extended to include a file upload page
5
5
  Home-page: https://github.com/Densaugeo/uploadserver
6
6
  Author: Densaugeo
@@ -203,6 +203,11 @@ options:
203
203
  - File field in upload form renamed from `file_1` to `files`, to reflect support for multiple file upload. Scripts using cURL will need to be upadted with the new field name.
204
204
  - Successful uploads now respond with 204 No Content instead of 200 OK, so that cURL will not default to printing the upload page at the terminal.
205
205
 
206
+ ## Security Issues
207
+
208
+ - Patched in `6.0.3`: Timing side channel. Introduced in `1.0.0`. Unpatched versions using the `--basic-auth`, `--basic-auth-upload`, or `--token` options are vulnerable to revealing password information through response timing.
209
+ - Patched in `6.0.2`: DoS vulnerability. Introduced in `4.1.0`. Unpatched versions using the `--basic-auth` or `--basic-auth-upload` options generate stack traces in response to certain requests, which could be used to pollute logs or exhaust storage.
210
+
206
211
  ## Acknowledgements
207
212
 
208
213
  Much of `main()` was copied from Python's `http.server`.
@@ -217,4 +222,6 @@ Thanks to shuangye for finding an easy way to handle large file uploads, and imp
217
222
 
218
223
  Thanks to abbbe for adding HTTP basic auth (has now replaced the token option).
219
224
 
220
- Thanks to SimarMugattarov, theo543, and poshul for minor updates.
225
+ Thanks to 0xLordMahesh for reporting the timing side channel and DoS vulnerabilities patched in 6.0.2 and 6.0.3.
226
+
227
+ Thanks to SimarMugattarov, theo543, poshul, and OnkarRuikar for minor updates.
File without changes
File without changes