In Ghost we have the ability to set a content type header for any custom route in routes.yaml, but otherwise, headers are not customisable.
There are many different headers that a user might want to set, the most common use case being to improve security. We should also provide a better default set of headers, as part of this.
We will provide the ability to upload a headers.yaml file. The file must contain valid YAML.
Headers will apply to the web application of Ghost only (same as redirects).
We will allow for setting headers per route with route matching exactly like Netlify _headers
The top level YAML keys represent rules, with wildcard matches.
Nested key value pairs should represent header names and values. Case should not matter.
/*:
Header-Name: Value
/something/*:
header-name: value
Real world example (taken from Ghost docs):
/*:
Referrer-Policy: no-referrer-when-downgrade
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
Feature-Policy: accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'
There may be some headers that Ghost sets which should be ignored if they are overridden via headers.yaml, to prevent any conflicts or issues on Ghost(Pro). The first that comes to mind is Cache-Control & Proxy headers.
Express also automatically sets X-Powered-By to express. It's always been tricky for us to remove because the setting doesn't cascade, and we have 4 different express apps. As part of this task we should remove X-Powered-By: express from everywhere.
Ghost currently does not set any security headers. This task includes deciding on and implementing a set of defaults for the frontend, admin and API. Defaults for the frontend should then be included as the default headers.yaml file, so that they can be overridden and extended.
At bare minimum we should have defaults something like those Ghost-CLI already sets:
/*:
Strict-Transport-Security 'max-age=63072000; includeSubDomains; preload';
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options nosniff;
Note: Because of the View Site feature in Ghost admin, the X-Frame-Options header should be set to allow-from admin.url if an admin url is set.
To determine a full set of defaults, we should review the headers set on docs: https://github.com/TryGhost/docs/commit/8af94d2c92d455738b940150cba56bf741ed9568 and the advisory info from securityheaders.com
If a user uploads a file without these defaults, they won't be set for the Ghost frontend.
It may be the case that the API & admin need slightly different or less default security headers, but we should still implement the best possible set we can without impacting users.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Not stale - note to self: need to update the bot to ignore the feature label
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Not stale - still relevant.