Comparison

mod_http_upload_external/README.md @ 6003:fe081789f7b5

All community modules: Unify file extention of Markdown files to .md
author Menel <menel@snikket.de>
date Tue, 22 Oct 2024 10:26:01 +0200
parent 5933:mod_http_upload_external/README.markdown@070b0db6c4a0
child 6093:c359259a494d
comparison
equal deleted inserted replaced
6002:5a65a632d5b9 6003:fe081789f7b5
1 ---
2 description: HTTP File Upload (external service)
3 labels:
4 - Stage-Alpha
5 ---
6
7 Introduction
8 ============
9
10 This module implements [XEP-0363], which lets clients upload files
11 over HTTP to an external web server.
12
13 This module generates URLs that are signed using a HMAC. Any web service that can authenticate
14 these URLs can be used.
15
16 Implementations
17 ---------------
18
19 * [PHP implementation](https://hg.prosody.im/prosody-modules/raw-file/tip/mod_http_upload_external/share.php)
20 * [Python3+Flask implementation](https://github.com/horazont/xmpp-http-upload)
21 * [Go implementation, Prosody Filer](https://github.com/ThomasLeister/prosody-filer)
22 * [Perl implementation for nginx](https://github.com/weiss/ngx_http_upload)
23 * [Rust implementation](https://gitlab.com/nyovaya/xmpp-http-upload)
24
25 To implement your own service compatible with this module, check out the implementation notes below
26 (and if you publish your implementation - let us know!).
27
28 Configuration
29 =============
30
31 The module can be added as a new Component definition:
32
33 ``` {.lua}
34 Component "upload.example.org" "http_upload_external"
35 http_upload_external_base_url = "https://your.example.com/upload/service"
36 http_upload_external_secret = "your shared secret"
37 ```
38
39 It should **not** be added to modules_enabled.
40
41
42 External URL
43 ------------
44
45 You need to provide the path to the external service. Ensure it ends with '/'.
46
47 For example, to use the PHP implementation linked above, you might set it to:
48
49 ``` {.lua}
50 http_upload_external_base_url = "https://your.example.com/path/to/share.php/"
51 ```
52
53 Secret
54 ------
55
56 Set a long and unpredictable string as your secret. This is so the upload service can verify that
57 the upload comes from mod_http_upload_external, and random strangers can't upload to your server.
58
59 ``` {.lua}
60 http_upload_external_secret = "this is a secret string!"
61 ```
62
63 You need to set exactly the same secret string in your external service.
64
65 Limits
66 ------
67
68 A maximum file size can be set by:
69
70 ``` {.lua}
71 http_upload_external_file_size_limit = 123 -- bytes
72 ```
73
74 Default is 100MB (100\*1024\*1024).
75
76 Access
77 ------
78
79 You may want to give upload access to additional entities such as components
80 by using the `http_upload_external_access` config option.
81
82 ``` {.lua}
83 http_upload_external_access = {"gateway.example.com"};
84 ```
85
86 Compatibility
87 =============
88
89 Works with Prosody 0.9.x and later.
90
91 Implementation
92 ==============
93
94 To implement your own external service that is compatible with this module, you need to expose a
95 simple API that allows the HTTP GET, HEAD and PUT methods on arbitrary URLs located on your service.
96
97 For example, if http_upload_external_base_url is set to `https://example.com/upload/` then your service
98 might receive the following requests:
99
100 Upload a new file:
101
102 ```
103 PUT https://example.com/upload/foo/bar.jpg?v=49e9309ff543ace93d25be90635ba8e9965c4f23fc885b2d86c947a5d59e55b2
104 ```
105
106 Recipient checks the file size and other headers:
107
108 ```
109 HEAD https://example.com/upload/foo/bar.jpg
110 ```
111
112 Recipient downloads the file:
113
114 ```
115 GET https://example.com/upload/foo/bar.jpg
116 ```
117
118 The only tricky logic is in validation of the PUT request. Firstly, don't overwrite existing files (return 409 Conflict).
119
120 Then you need to validate the auth token.
121
122 ### Validating the auth token
123
124
125 | Version | Supports |
126 |:--------|:--------------------------------------------------------------------------------------------------------|
127 | v | Validates only filename and size. Does not support file type restrictions by the XMPP server. |
128 | v2 | Validates the filename, size and MIME type. This allows the server to implement MIME type restrictions. |
129
130 It is probable that a future v3 will be specified that allows carrying information about the uploader identity, allowing
131 the implementation of per-user quotas and limits.
132
133 Implementations may implement one or more versions of the protocol simultaneously. The XMPP server generates the URLs and
134 ultimately selects which version will be used.
135
136 XMPP servers MUST only generate URLs with **one** of the versions listed here. However in case multiple parameters are
137 present, upload services MUST **only** use the token from the highest parameter version that they support.
138
139 #### Version 1 (v)
140
141 The token will be in the URL query parameter 'v'. If it is absent, fail with 403 Forbidden.
142
143 Calculate the expected auth token by reading the value of the Content-Length header of the PUT request. E.g. for a 1MB file
144 will have a Content-Length of '1048576'. Append this to the uploaded file name, separated by a space (0x20) character.
145
146 For the above example, you would end up with the following string: "foo/bar.jpg 1048576"
147
148 The auth token is a SHA256 HMAC of this string, using the configured secret as the key. E.g.
149
150 ```
151 calculated_auth_token = hmac_sha256("foo/bar.jpg 1048576", "secret string")
152 ```
153
154 If this is not equal to the 'v' parameter provided in the upload URL, reject the upload with 403 Forbidden.
155
156 **Security note:** When comparing `calculated_auth_token` with the token provided in the URL, you must use a constant-time string
157 comparison, otherwise an attacker may be able to discover your secret key. Most languages/environments provide such a function, such
158 as `hash_equals()` in PHP, `hmac.compare_digest()` in Python, or `ConstantTimeCompare()` from `crypto/subtle` in Go.
159
160 #### Version 2 (v2)
161
162 The token will be in the URL query parameter 'v2'. If it is absent, fail with 403 Forbidden.
163
164 | Input | Example |Read from |
165 |:----------------|:------------|:--------------------------------------------------------------------|
166 |`file_path` | foo/bar.jpg | The URL of the PUT request, with the service's base prefix removed. |
167 |`content_length` | 1048576 | Content-Length header |
168 |`content_type` | image/jpeg | Content-Type header |
169
170 The parameters should be joined into a single string, separated by NUL bytes (`\0`):
171
172 ```
173 signed_string = ( file_path + '\0' + content_length + '\0' + content_type )
174 ```
175
176 ```
177 signed_string = "foo/bar.jpg\01048576\0image/jpeg"
178 ```
179
180 The expected auth token is the SHA256 HMAC of this string, using the configured secret key as the key. E.g.:
181
182 ```
183 calculated_auth_token = hmac_sha256(signed_string, "secret string")
184 ```
185
186 If this is not equal to the 'v2' parameter provided in the upload URL, reject the upload with 403 Forbidden.
187
188 **Security note:** When comparing `calculated_auth_token` with the token provided in the URL, you must use a constant-time string
189 comparison, otherwise an attacker may be able to discover your secret key. Most languages/environments provide such a function, such
190 as `hash_equals()` in PHP, `hmac.compare_digest()` in Python, or `ConstantTimeCompare()` from `crypto/subtle` in Go.
191
192 ### Security considerations
193
194 #### HTTPS
195
196 All uploads and downloads should only be over HTTPS. The security of the served content is protected only
197 by the uniqueness present in the URLs themselves, and not using HTTPS may leak the URLs and contents to third-parties.
198
199 Implementations should consider including HSTS and HPKP headers, with consent of the administrator.
200
201 #### MIME types
202
203 If the upload Content-Type header matches any of the following MIME types, it MUST be preserved and included in the Content-Type
204 of any GET requests made to download the file:
205
206 - `image/*`
207 - `video/*`
208 - `audio/*`
209 - `text/plain`
210
211 It is recommended that other MIME types are preserved, but served with the addition of the following header:
212
213 ```
214 Content-Disposition: attachment
215 ```
216
217 This prevents the browser interpreting scripts and other resources that may potentially be malicious.
218
219 Some browsers may also benefit from explicitly telling them not to try guessing the type of a file:
220
221 ```
222 X-Content-Type-Options: nosniff
223 ```
224
225 #### Security headers
226
227 The following headers should be included to provide additional sandboxing of resources, considering the uploaded
228 content is not understood or trusted by the upload service:
229
230 ```
231 Content-Security-Policy: default-src 'none'
232 X-Content-Security-Policy: default-src 'none'
233 X-WebKit-CSP: default-src 'none'
234 ```