Repository navigation
CSP configuration
Tip
TL;DR raw_csp in config/raw.config.php sets CSPs by token, path, extension or MIME type.
The rules apply to all shares. The order in which selectors and the per-share CSP are tried is described in Content Security Policy.
A policy may be written as
- a string: a complete single-line header value, passed through after control characters and repeated whitespace are removed;
- an indexed array: directive strings, joined with
;; - an associative array (recommended):
'directive' => sources, wheresourcesis a space-separated string or an array of strings. Sources are deduplicated, directives are put into a fixed order and joined into one header line.
In the associative format only these directive names are accepted; unknown ones are skipped. String and indexed policies are not filtered.
| Group | Directives |
|---|---|
| Fetch, fallbacks |
default-src, script-src, style-src, child-src
|
| Fetch, common |
connect-src, font-src, frame-src, img-src, manifest-src, media-src, object-src, worker-src
|
| Document |
base-uri, sandbox
|
| Navigation |
form-action, frame-ancestors
|
| Other | upgrade-insecure-requests |
| Selector | Key | Matches |
|---|---|---|
token |
share token | the token of a public share URL; never a private URL |
path_prefix |
starts with /raw or /rss
|
absolute prefix of the request path, longest match wins |
path_prefix |
anything else | prefix of the path after the token (public) or after /u/{user} (private), longest match wins |
path_contains |
substring | the full request path or the path after the token or user |
extension |
html, json, ... |
file extension, lower case |
mimetype |
text/html, ... |
MIME type, lower case |
- A pattern starting with a slash, for example
'/html/', matches only that exact sequence, so it targets a folder segment. - A pattern without a leading slash, for example
'html', is a plain substring and matches/some_html_text/,/some-html-data/,/htmlfileand/html/alike.
Use '/folder/' to match a folder exactly, and a plain word only when the broad match is intended.
<?php
$CONFIG = array (
'raw_csp' =>
array(
'extension' =>
array(
'html' =>
array(
'default-src' => ["'self'"],
'script-src' => ["'self'", "'unsafe-inline'"],
'img-src' => ["'self'", "data:"],
'media-src' => ["data:"],
'style-src' => ["'self'", "'unsafe-inline'"],
'font-src' => ["data:"],
'frame-src' => ["'none'"],
),
),
),
);<?php
$CONFIG = array (
'raw_csp' =>
array(
'path_prefix' =>
array(
// absolute: everything below the share with the token 'special-html'
'/raw/special-html/' =>
array(
'default-src' => ["'self'"],
'script-src' => ["'self'"],
),
// relative: matched against the path after the token or after /u/{user}
'html/' =>
array(
'default-src' => ["'self'"],
'script-src' => ["'self'", "'unsafe-inline'"],
'img-src' => ["'self'", "data:"],
),
),
),
);<?php
$CONFIG = array (
'raw_csp' =>
array(
'path_contains' =>
array(
'/html/' =>
array(
'default-src' => ["'self'"],
'script-src' => ["'self'"],
'img-src' => ["'self'", "data:"],
'style-src' => ["'self'", "'unsafe-inline'"],
),
),
),
);<?php
$CONFIG = array (
'raw_csp' =>
array(
'token' =>
array(
'abc123' =>
array(
'default-src' => ["'self'"],
'img-src' => ["'self'", "data:"],
),
),
),
);<?php
$CONFIG = array (
'raw_csp' =>
array(
'path_prefix' =>
array(
'html/' =>
array(
'default-src' => ["'self'"],
'script-src' => ["'self'", "'unsafe-inline'"],
),
),
'path_contains' =>
array(
'/public/static/' =>
array(
'default-src' => ["'self'"],
'img-src' => ["'self'", "data:"],
),
),
'extension' =>
array(
'json' =>
array(
'default-src' => ["'none'"],
'img-src' => ["data:"],
),
),
),
);raw_csp is read on every request, so a change applies immediately. Check the header:
curl -sI 'https://cloud.example.com/raw/html/calc.html' | grep -i '^content-security-policy'
curl -sI 'https://cloud.example.com/raw/u/alice/Documents/html/calc.html' | grep -i '^content-security-policy'If the policy is not the expected one:
- check that the selector fits the URL form (token, path, extension);
- check that no selector earlier in the matching order catches the request first;
- remember that
tokennever matches private URLs.
Getting started
Controlling access
Security headers
Performance
Reference