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 ```