Specify `Content-Type` and `Content-Disposition` usage in the media repo (#1935)

pull/1941/head
Kévin Commaille 2 months ago committed by GitHub
parent 7f2f100420
commit 415fb43848
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1 @@
Specify `Content-Type` and `Content-Disposition` usage in the media repo, as per [MSC2701](https://github.com/matrix-org/matrix-spec-proposals/pull/2701) and [MSC2702](https://github.com/matrix-org/matrix-spec-proposals/pull/2702).

@ -168,3 +168,50 @@ Homeservers have additional content-specific concerns:
- Clients or remote homeservers may try to upload malicious files - Clients or remote homeservers may try to upload malicious files
targeting vulnerabilities in either the homeserver thumbnailing or targeting vulnerabilities in either the homeserver thumbnailing or
the client decoders. the client decoders.
##### Serving inline content
Clients with insecure configurations may be vulnerable to Cross-Site Scripting
attacks when served media with a `Content-Disposition` of `inline`. Clients
SHOULD NOT be hosted on the same domain as the media endpoints for the homeserver
to mitigate most of this risk. Servers SHOULD restrict `Content-Type` headers to
one of the following values when serving content with `Content-Disposition: inline`:
* `text/css`
* `text/plain`
* `text/csv`
* `application/json`
* `application/ld+json`
* `image/jpeg`
* `image/gif`
* `image/png`
* `image/apng`
* `image/webp`
* `image/avif`
* `video/mp4`
* `video/webm`
* `video/ogg`
* `video/quicktime`
* `audio/mp4`
* `audio/webm`
* `audio/aac`
* `audio/mpeg`
* `audio/ogg`
* `audio/wave`
* `audio/wav`
* `audio/x-wav`
* `audio/x-pn-wav`
* `audio/flac`
* `audio/x-flac`
These types are unlikely to cause Cross-Site Scripting issues when a `Content-Type`
header is provided, as clients will only try to render the data using that content
type. For example, if a HTML file is uploaded with a `Content-Type` of `image/png`,
clients will just assume that the image is corrupted, and won't render it as a
HTML page. Therefore, there is no risk in trusting the user-defined content type,
as long as the `Content-Disposition` is calculated based on that type.
Clients SHOULD NOT rely on servers returning `inline` rather than `attachment`
on `/download`. Server implementations might decide out of an abundance of
caution that all downloads are responded to with `attachment`, regardless of
content type - clients should not be surprised by this behaviour.

@ -46,9 +46,29 @@ paths:
Content-Type: Content-Type:
$ref: '#/components/headers/downloadContentType' $ref: '#/components/headers/downloadContentType'
Content-Disposition: Content-Disposition:
description: The name of the file that was previously uploaded, if set. x-changedInMatrixVersion:
"1.12": This header became required.
description: |
The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
of the returned content. MUST be one of `inline` or `attachment`,
and SHOULD contain a file name.
If the `Content-Type` is allowed in the [restrictions for serving
inline content](/client-server-api/#serving-inline-content),
servers SHOULD use `inline`, otherwise they SHOULD use
`attachment`.
If the upload was made with a `filename`, this header MUST
contain the same `filename`. Otherwise, `filename` is excluded
from the header. If the media being downloaded is remote, the
remote server's `filename` in the `Content-Disposition` header
is used as the `filename` instead. When the header is not
supplied, or does not supply a `filename`, the local download
response does not include a `filename`.
required: true
schema: schema:
type: string type: string
example: "inline; filename=\"filename.jpg\""
content: content:
application/octet-stream: application/octet-stream:
schema: schema:
@ -106,11 +126,21 @@ paths:
Content-Type: Content-Type:
$ref: '#/components/headers/downloadContentType' $ref: '#/components/headers/downloadContentType'
Content-Disposition: Content-Disposition:
description: |- x-changedInMatrixVersion:
The `fileName` requested or the name of the file that was previously "1.12": This header became required.
uploaded, if set. description: |
The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
of the returned content. MUST be one of `inline` or `attachment`,
and MUST contain the file name requested in the path.
If the `Content-Type` is allowed in the [restrictions for serving
inline content](/client-server-api/#serving-inline-content),
servers SHOULD use `inline`, otherwise they SHOULD use
`attachment`.
required: true
schema: schema:
type: string type: string
example: "inline; filename=\"filename.jpg\""
content: content:
application/octet-stream: application/octet-stream:
schema: schema:
@ -208,8 +238,24 @@ paths:
"200": "200":
description: A thumbnail of the requested content. description: A thumbnail of the requested content.
headers: headers:
Content-Disposition:
x-addedInMatrixVersion: "1.12"
description: |
The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
of the returned content. MUST be `inline`, and SHOULD contain a file name (e.g. `thumbnail.png`).
Servers should note the [Content-Type restrictions for serving inline content](/client-server-api/#serving-inline-content),
as these limitations imply which formats should be used for thumbnail generation.
required: true
schema:
type: string
example: "inline; filename=\"thumbnail.png\""
Content-Type: Content-Type:
x-changedInMatrixVersion:
"1.12": |
This header became required in order to support `Content-Disposition`.
description: The content type of the thumbnail. description: The content type of the thumbnail.
required: true
schema: schema:
type: string type: string
enum: enum:
@ -512,7 +558,29 @@ components:
format: uri format: uri
headers: headers:
downloadContentType: downloadContentType:
description: The content type of the file that was previously uploaded. description: |
The content type of the file that was previously uploaded.
The server MUST return a `Content-Type` which is either exactly the same
as the original upload, or reasonably close. The bounds of "reasonable"
are:
* Adding a charset to `text/*` content types.
* Detecting HTML and using `text/html` instead of `text/plain`.
* Using `application/octet-stream` when the server determines the
content type is obviously wrong. For example, an encrypted file being
claimed as `image/png`.
* Returning `application/octet-stream` when the media has an
unknown/unprovided `Content-Type`. For example, being uploaded before
the server tracked content types or when the remote server is
non-compliantly omitting the header entirely.
Actions not in the spirit of the above are not considered "reasonable".
x-changedInMatrixVersion:
"1.12": |
This header became required in order to support `Content-Disposition`,
and the behaviour to compute its value was clarified.
required: true
schema: schema:
type: string type: string

@ -248,9 +248,29 @@ paths:
Content-Type: Content-Type:
$ref: '#/components/headers/downloadContentType' $ref: '#/components/headers/downloadContentType'
Content-Disposition: Content-Disposition:
description: The name of the file that was previously uploaded, if set. x-changedInMatrixVersion:
"1.12": This header became required.
description: |
The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
of the returned content. MUST be one of `inline` or `attachment`,
and SHOULD contain a file name.
If the `Content-Type` is allowed in the [restrictions for serving
inline content](/client-server-api/#serving-inline-content),
servers SHOULD use `inline`, otherwise they SHOULD use
`attachment`.
If the upload was made with a `filename`, this header MUST
contain the same `filename`. Otherwise, `filename` is excluded
from the header. If the media being downloaded is remote, the
remote server's `filename` in the `Content-Disposition` header
is used as the `filename` instead. When the header is not
supplied, or does not supply a `filename`, the local download
response does not include a `filename`.
required: true
schema: schema:
type: string type: string
example: "inline; filename=\"filename.jpg\""
content: content:
application/octet-stream: application/octet-stream:
schema: schema:
@ -309,11 +329,21 @@ paths:
Content-Type: Content-Type:
$ref: '#/components/headers/downloadContentType' $ref: '#/components/headers/downloadContentType'
Content-Disposition: Content-Disposition:
description: |- x-changedInMatrixVersion:
The `fileName` requested or the name of the file that was previously "1.12": This header became required.
uploaded, if set. description: |
The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
of the returned content. MUST be one of `inline` or `attachment`,
and MUST contain the file name requested in the path.
If the `Content-Type` is allowed in the [restrictions for serving
inline content](/client-server-api/#serving-inline-content),
servers SHOULD use `inline`, otherwise they SHOULD use
`attachment`.
required: true
schema: schema:
type: string type: string
example: "inline; filename=\"filename.jpg\""
content: content:
application/octet-stream: application/octet-stream:
schema: schema:
@ -412,8 +442,24 @@ paths:
"200": "200":
description: A thumbnail of the requested content. description: A thumbnail of the requested content.
headers: headers:
Content-Disposition:
x-addedInMatrixVersion: "1.12"
description: |
The [disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition)
of the returned content. MUST be `inline`, and SHOULD contain a file name (e.g. `thumbnail.png`).
Servers should note the [Content-Type restrictions for serving inline content](/client-server-api/#serving-inline-content),
as these limitations imply which formats should be used for thumbnail generation.
required: true
schema:
type: string
example: "inline; filename=\"thumbnail.png\""
Content-Type: Content-Type:
x-changedInMatrixVersion:
"1.12": |
This header became required in order to support `Content-Disposition`.
description: The content type of the thumbnail. description: The content type of the thumbnail.
required: true
schema: schema:
type: string type: string
enum: enum:
@ -639,7 +685,15 @@ components:
contentType: contentType:
in: header in: header
name: Content-Type name: Content-Type
description: The content type of the file being uploaded description: |
**Optional.** The content type of the file being uploaded.
Clients SHOULD always supply this header.
Defaults to `application/octet-stream` if it is not set.
x-changedInMatrixVersion:
"1.12": |
This header became explicitly optional with a default value.
example: application/pdf example: application/pdf
schema: schema:
type: string type: string
@ -782,7 +836,29 @@ components:
format: uri format: uri
headers: headers:
downloadContentType: downloadContentType:
description: The content type of the file that was previously uploaded. description: |
The content type of the file that was previously uploaded.
The server MUST return a `Content-Type` which is either exactly the same
as the original upload, or reasonably close. The bounds of "reasonable"
are:
* Adding a charset to `text/*` content types.
* Detecting HTML and using `text/html` instead of `text/plain`.
* Using `application/octet-stream` when the server determines the
content type is obviously wrong. For example, an encrypted file being
claimed as `image/png`.
* Returning `application/octet-stream` when the media has an
unknown/unprovided `Content-Type`. For example, being uploaded before
the server tracked content types or when the remote server is
non-compliantly omitting the header entirely.
Actions not in the spirit of the above are not considered "reasonable".
x-changedInMatrixVersion:
"1.12": |
This header became required in order to support `Content-Disposition`,
and the behaviour to compute its value was clarified.
required: true
schema: schema:
type: string type: string

Loading…
Cancel
Save