mod_http_upload_external/README.markdown
changeset 3362 e49660ba3161
parent 3193 57332ea0c1c7
child 3363 3d01ab6b1186
equal deleted inserted replaced
3361:af824168729a 3362: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 ```