Mercurial > prosody-modules
comparison mod_http_upload_external/README.markdown @ 3358:e49660ba3161
mod_http_upload_external: Improve implementation docs, including v2 details
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Sun, 21 Oct 2018 14:54:19 +0100 |
| parents | 57332ea0c1c7 |
| children | 3d01ab6b1186 |
comparison
equal
deleted
inserted
replaced
| 3357:af824168729a | 3358:e49660ba3161 |
|---|---|
| 95 GET https://example.com/upload/foo/bar.jpg | 95 GET https://example.com/upload/foo/bar.jpg |
| 96 ``` | 96 ``` |
| 97 | 97 |
| 98 The only tricky logic is in validation of the PUT request. Firstly, don't overwrite existing files (return 409 Conflict). | 98 The only tricky logic is in validation of the PUT request. Firstly, don't overwrite existing files (return 409 Conflict). |
| 99 | 99 |
| 100 Then you need to validate the auth token. This will be in the URL query parameter 'v'. If it is absent, fail with 403 Forbidden. | 100 Then you need to validate the auth token. |
| 101 | |
| 102 ### Validating the auth token | |
| 103 | |
| 104 | |
| 105 | Version | Supports | | |
| 106 |:--------|:--------------------------------------------------------------------------------------------------------| | |
| 107 | v | Validates only filename and size. Does not support file type restrictions by the XMPP server. | | |
| 108 | v2 | Validates the filename, size and MIME type. This allows the server to implement MIME type restrictions. | | |
| 109 | |
| 110 It is probable that a future v3 will be specified that allows carrying information about the uploader identity, allowing | |
| 111 the implementation of per-user quotas and limits. | |
| 112 | |
| 113 Implementations may implement one or more versions of the protocol simultaneously. The XMPP server generates the URLs and ultimately selects which version will be used. | |
| 114 | |
| 115 #### Version 1 (v) | |
| 116 | |
| 117 The token will be in the URL query parameter 'v'. If it is absent, fail with 403 Forbidden. | |
| 101 | 118 |
| 102 Calculate the expected auth token by reading the value of the Content-Length header of the PUT request. E.g. for a 1MB file | 119 Calculate the expected auth token by reading the value of the Content-Length header of the PUT request. E.g. for a 1MB file |
| 103 will have a Content-Length of '1048576'. Append this to the uploaded file name, separated by a space (0x20) character. | 120 will have a Content-Length of '1048576'. Append this to the uploaded file name, separated by a space (0x20) character. |
| 104 | 121 |
| 105 For the above example, you would end up with the following string: "foo/bar.jpg 1048576" | 122 For the above example, you would end up with the following string: "foo/bar.jpg 1048576" |
| 110 calculated_auth_token = hmac_sha256("foo/bar.jpg 1048576", "secret string") | 127 calculated_auth_token = hmac_sha256("foo/bar.jpg 1048576", "secret string") |
| 111 ``` | 128 ``` |
| 112 | 129 |
| 113 If this is not equal to the 'v' parameter provided in the upload URL, reject the upload with 403 Forbidden. | 130 If this is not equal to the 'v' parameter provided in the upload URL, reject the upload with 403 Forbidden. |
| 114 | 131 |
| 115 Note: your language/environment may provide a function for doing a constant-time comparison of these, to guard against | 132 **Security note:** When comparing `calculated_auth_token` with the token provided in the URL, you must use a constant-time string |
| 116 timing attacks that may be used to discover the secret key. | 133 comparison, otherwise an attacker may be able to discover your secret key. Most languages/environments provide such a function, such |
| 134 as `hash_equals()` in PHP, `hmac.compare_digest()` in Python, or `ConstantTimeCompare()` from `crypto/subtle` in Go. | |
| 135 | |
| 136 #### Version 2 (v2) | |
| 137 | |
| 138 The token will be in the URL query parameter 'v2'. If it is absent, fail with 403 Forbidden. | |
| 139 | |
| 140 | Input | Example |Read from | | |
| 141 |:--------------|:------------|:--------------------------------------------------------------------| | |
| 142 |`file_path` | foo/bar.jpg | The URL of the PUT request, with the service's base prefix removed. | | |
| 143 |`content_size` | 1048576 | Content-Size header | | |
| 144 |`content_type` | image/jpeg | Content-Type header | | |
| 145 | |
| 146 The parameters should be joined into a single string, separated by NUL bytes (`\0`): | |
| 147 | |
| 148 ``` | |
| 149 signed_string = ( file_path + '\0' + content_size + '\0' + content_type ) | |
| 150 ``` | |
| 151 | |
| 152 ``` | |
| 153 signed_string = "foo/bar.jpg\01048576\0image/jpeg" | |
| 154 ``` | |
| 155 | |
| 156 The expected auth token is the SHA256 HMAC of this string, using the configured secret key as the key. E.g.: | |
| 157 | |
| 158 ``` | |
| 159 calculated_auth_token = hmac_sha256(signed_string, "secret string") | |
| 160 ``` | |
| 161 | |
| 162 If this is not equal to the 'v2' parameter provided in the upload URL, reject the upload with 403 Forbidden. | |
| 163 | |
| 164 **Security note:** When comparing `calculated_auth_token` with the token provided in the URL, you must use a constant-time string | |
| 165 comparison, otherwise an attacker may be able to discover your secret key. Most languages/environments provide such a function, such | |
| 166 as `hash_equals()` in PHP, `hmac.compare_digest()` in Python, or `ConstantTimeCompare()` from `crypto/subtle` in Go. | |
| 167 | |
| 168 ### Security considerations | |
| 169 | |
| 170 #### HTTPS | |
| 171 | |
| 172 All uploads and downloads should only be over HTTPS. The security of the served content is protected only | |
| 173 by the uniqueness present in the URLs themselves, and not using HTTPS may leak the URLs and contents to third-parties. | |
| 174 | |
| 175 Implementations should consider including HSTS and HPKP headers, with consent of the administrator. | |
| 176 | |
| 177 #### MIME types | |
| 178 | |
| 179 If the upload Content-Type header matches any of the following MIME types, it MUST be preserved and included in the Content-Type | |
| 180 of any GET requests made to download the file: | |
| 181 | |
| 182 - `image/*` | |
| 183 - `video/*` | |
| 184 - `audio/*` | |
| 185 - `text/plain` | |
| 186 | |
| 187 It is recommended that other MIME types are preserved, but served with the addition of the following header: | |
| 188 | |
| 189 ``` | |
| 190 Content-Disposition: attachment | |
| 191 ``` | |
| 192 | |
| 193 This prevents the browser interpreting scripts and other resources that may potentially be malicious. | |
| 194 | |
| 195 Some browsers may also benefit from explicitly telling them not to try guessing the type of a file: | |
| 196 | |
| 197 ``` | |
| 198 X-Content-Type-Options "nosniff" | |
| 199 ``` | |
| 200 | |
| 201 #### Security headers | |
| 202 | |
| 203 The following headers should be included to provide additional sandboxing of resources, considering the uploaded | |
| 204 content is not understood or trusted by the upload service: | |
| 205 | |
| 206 ``` | |
| 207 Content-Security-Policy: "default-src 'none'" | |
| 208 X-Content-Security-Policy: "default-src 'none'" | |
| 209 X-WebKit-CSP: "default-src 'none'" | |
| 210 ``` |
