silverstripe-framework/docs/en/04_Changelogs/4.4.6.md

449 lines
20 KiB
Markdown

# 4.4.6
## Security patches
This release is a security hotfix. It only contains security fixes essential to
addressing the CVE-2020-9280 security issue and follow up work from the
CVE-2019-12245 patch which was released in September 2019.
* [Read the CVE-2020-9280 security disclosure](https://www.silverstripe.org/download/security-releases/CVE-2020-9280)
from April 2020
* [Read the CVE-2019-12245 security disclosure](https://www.silverstripe.org/download/security-releases/CVE-2019-12245)
from September 2019
**Simply applying the patch might NOT be enough.** Some files that were uploaded
or created prior to the application of the CVE-2020-9280/CVE-2019-12245 patches
may be left exposed to the public. You may need to run some additional file
migration tasks to protect those files.
This release is especially important for Silverstripe CMS projects using the
`silverstripe/userforms` module, but all project owners should consider
upgrading as soon as convenient.
If your project was migrated from Silverstripe CMS 3, you need to run the new
`migrate-folders` task.
## What does this release fix?
### CVE-2020-9280: Folders migrated from Silverstripe CMS 3 may be unsafe to upload to (CVSS 5.9)
Files uploaded via Forms to folders migrated from Silverstripe CMS 3.x may be
put to the default `/Uploads` folder instead. Uploads performed via the CMS UI
are not affected. This is a security issue because the default `/Uploads` folder
is publicly accessible by default, which means the uploaded files may be
accessed by unauthorised parties via HTTP by guessing the file name. This
affects installations which allowed upload folder protection via the optional
`silverstripe/secureassets` module under 3.x. This module is installed and
enabled by default on the Common Web Platform (CWP). The vulnerability only
affects files uploaded after an upgrade to 4.x.
[Read the CVE-2020-9280 security disclosure](https://www.silverstripe.org/download/security-releases/CVE-2020-9280)
### CVE-2019-12245 follow up work
In September 2019, Silverstripe CMS 4.3.6 and 4.4.4 were released to address an
issue that caused files to be stored in a publicly accessible location. Files
that were uploaded via the userforms module could have been affected. Files
uploaded via a custom form or programmatically created could also have been
affected.
While those older releases prevented the exposure of new files, they did not
retroactively protect files that had already been exposed prior to the patch.
These new releases provide a mechanism to protect files wrongly exposed to the
public.
* [Read the CVE-2019-12245 security disclosure](https://www.silverstripe.org/download/security-releases/CVE-2019-12245)
* [Read the Silverstripe CMS 4.3.6 change logs](4.3.6)
* [Read the Silverstripe CMS 4.4.4 change logs](4.4.4)
## What are the technical details of the vulnerabilities?
### CVE-2020-9280
The root cause of the problem is that the file migration task would not create
"Live" records for Folders migrated from Silverstripe CMS 3 prior to this patch.
This may lead to inconsistencies between the database state and what the actual
application gets from the ORM when performing its business logic.
This affects the `silverstripe/userforms` module and can cause user forms to
save uploaded files in the default "Uploads" folder. Custom forms built with
`Silverstripe\Forms` or `Silverstripe\Assets` components can also be
susceptible to this behaviour.
Considering user forms as an example. Let's say you have an EditableFileField,
that keeps an ID of a folder to upload to as an `has_one` relationship. When the
submission happens with a `Stage=Live` context, the ORM cannot fetch the
`Folder` instance, since it doesn't exist in the `Live` stage. When the upload
Folder is undefined, the default `Silverstripe\FileField` implementation falls
back to the default "Uploads" Folder, which is public by default.
### CVE-2019-12245
Prior the 4.3.6/4.4.4 release, the `File::canView()` method could
return an erroneous value for anonymous users when the file was being created or
uploaded from a "Live" stage. When creating a new File in a Live stage, this
could cause the file to be stored in a publicly accessible location when it was
meant to be protected.
This could occur when:
* a file was submitted in a user form upload field
* a file was submitted in a custom form
* a file was programmatically created by custom logic.
It would not occur when uploading a file via the asset administration area in
the CMS.
### How do I know if the files are actually exposed?
Even if your project creates files programmatically or receives them via a
custom form, your files might not have been exposed. Whether your files have
been exposed depends on your exact implementation.
There's two ways to verify if files are exposed:
* look directly at the file system
* try to access files in an incognito/private browser session.
If you have direct access to the file system or to a snapshot of your live data,
you can look directly at the files. To do that, access your `assets` directory
which will either be located in your project root or under the `public`
directory. The assets directory will contain an hidden `.protected` directory
which contains restricted and draft files. Other files which are not stored
under the `.protected` directory will be visible to anonymous users. If you can
see files that are meant to be confidential outside of the `.protected` folder,
then they are accessible by the general public.
Some files may be stored under a _hash path_. This means that the physical files
will be stored in a folder with a 10 character hexadecimal name. e.g.: If your
File is stored under `secret/folder/condfidential.pdf` in the CMS, the physical
file might be stored under a path similar to
`public/assets/secret/folder/c0f7cbd745/condfidential.pdf`.
[Learn what's the difference between _natural paths_ and _hash paths_](https://docs.silverstripe.org/en/4/developer_guides/files/file_migration/#natural-path-vs-hash-path)
on the Silverstripe CMS documentation.
Alternatively, you can try accessing the file directly in a incognito/private
browser session. To do so, navigate to a restricted file in the asset
administration interface inside the CMS. On the right-hand panel,
right-click on the file preview and copy the link to the file. If you paste the
link into a private/incognito browser session and can access the file, then your
file can be viewed by the general public.
## Running the migration tasks
The 4.4.6/4.5.2 Silverstripe CMS releases add new file migration subtasks to
retroactively protect files that have been wrongly exposed. They are 3 new
subtasks.
* `migrate-folders` creates versioning metadata for Silverstripe CMS 3 Folder
records.
* `normalise-access` protect files that have been wrongly exposed.
* `relocate-userform-uploads-2020-9280` move files uploaded through the
userforms module to their intended folder.
### Do I need to run the migration tasks?
Based on the nature of your Silverstripe CMS project, you may need to run all of
the tasks, some of the them, or none of them.
You do not need to run any of the subtasks if the following three conditions are
all true:
* your project was not migrated from Silverstripe CMS 3
* your project does not include the userforms module, or if it does, no userform
has been configured to allow file uploads
* your project does not programmatically create files or allow users to upload
files via a custom form(s).
If your project was upgraded from a Silverstripe CMS 3 project, you should
minimally run the `migrate-folders` subtask.
If your project programmatically creates files or allows users to upload files
via a user form or a custom form, you should run the `normalise-access` task.
If your project allows users to upload files via a user form and was upgraded from
a Silverstripe CMS 3 project, you may need to run all 3 tasks.
If your project was migrated from Silverstripe CMS 3 and allows users to upload
files via custom forms, you should run the `migrate-folders` subtask. However,
you also will need to manually protect the affected files. The easiest way
could be to find all the folders affected through a SQL query before you run the
task. Then you may be able to find all the custom forms using those folder IDs
accordingly. Unfortunately, we cannot provide any automation for this scenario.
You should also consider making your `/Uploads` folder protected manually
(via CMS) as a best practice, since it is publicly accessible by default.
### What do the migration tasks do?
Take some time to read the following descriptions and understand how running
each subtask will affect your Silverstripe CMS project. `migrate-folders` and
`normalise-access` are relatively quick and have no side affects.
`relocate-userform-uploads-2020-9280` is the most complex of the three subtasks
and has the most potential side effects. You should take special care to
understand what it does before running it.
#### migrate-folders subtask
The `migrate-folders` subtask validates that every "Folder" record in the
`File` table has a matching entry in the `File_Live` table. This will prevent
future file uploads from being accidentally stored in the publicly accessible
"Uploads" folder.
It does not retroactively move files that have been stored in the wrong Folder
to their intended destination.
To find out what Folders on your Silverstripe CMS project will be affected by
running the `migrate-folders` subtask, you can run the following SQL query:
```sql
-- This query is targeted to MySQL. You may need to adapt it for other SQL databases.
SELECT
File.ID,
File.Name
FROM
File
LEFT JOIN
File_Live
ON File_Live.ID = File.ID
WHERE
File_Live.ID IS NULL
AND File.ClassName = 'SilverStripe\\Assets\\Folder'
```
Note that the file migration task will now run this step by default, so you
won't need to explicitly run the `migrate-folders` task for future
Silverstripe CMS 3 upgrades.
[Learn how to migrate files from Silverstripe CMS 3 to Silverstripe CMS 4](https://docs.silverstripe.org/en/4/developer_guides/files/file_migration/#migration-from-silverstripe-3-to-silverstripe-4-4-or-later)
on the Silverstripe CMS documentation.
#### normalise-access subtask
The `normalise-access` subtask goes through each individual File record in a
Silverstripe CMS project and confirms that the `canView` result for anonymous
users matches the physical location of the file. If the physical file is
publicly visible while it's `canView` method returns `false` for anonymous
users, it will be moved to the protected location.
#### relocate-userform-uploads-2020-9280 task
Because of the `CVE-2020-9280` vulnerability, you may have Folders without a
matching entries in their "Live" table. User form file upload submissions
may end up being stored in an incorrect publicly-accessible location under the
following conditions:
* you have user forms that accept file uploads
* the file upload field is configured to save the file in a folder that was
created in Silverstripe CMS 3
* the targeted folder has not been manually saved since your Silverstripe CMS 4
upgrade.
If those 3 conditions are met, you should consider running the
`relocate-userform-uploads-2020-9280` subtask.
`relocate-userform-uploads-2020-9280` will go through each user form file upload
submission and verify that the uploaded file is stored in the folder specified
in the matching file upload user form field. If the file is stored in the wrong
folder, the task will move the file to the Folder specified in the user form
upload field configuration at the time the file was uploaded.
##### What if I have a custom upload form?
If you have a written a controller operating in the "Live" stage that creates
files or receives uploaded files, and that controller is configured to save
files in a folder created in Siverstripe CMS 3, your files may have been stored
in the wrong location. Unfortunately, we can not provide a migration task for
each custom scenario.
The `relocate-userform-uploads-2020-9280` only works because there's a record of
where the file was meant to be uploaded on the user form page.
If you have a small number of files, it might be practical to manually update
their location via the asset administration interface in the CMS. Otherwise, you
may have to write your own migration task to achieve the same purpose.
### How do I run the migration tasks?
`migrate-folders`, `normalise-access` and `relocate-userform-uploads-2020-9280`
have been written as subtasks of the regular file migration task. The file
migration task can be run in 3 different ways:
* in the browser under `dev/tasks`
* on the command line
* as a queued job.
You can run each subtask individually or you can run all three subtasks in one
go. The `only` parameter controls which subtasks will be run. You can get
multiple subtask to run by specifying them as a comma-separated list:
`only=migrate-folders,normalise-access,relocate-userform-uploads-2020-9280`. The subtasks
are executed in a pre-defined sequence, so the order they appeared in the
comma-separated list is irrelevant.
Which ever way you choose to run the sub tasks, you **MUST run `migrate-folders`
before `relocate-userform-uploads-2020-9280`**. The recommended order to run the subtasks
is:
1. `migrate-folders`
2. `normalise-access`
3. `relocate-userform-uploads-2020-9280`.
[Learn more about the File Migration Task on the Silverstripe CMS documentation](https://docs.silverstripe.org/en/4/developer_guides/files/file_migration/)
#### Testing the file migration task first
If possible, you should consider running the task in a development or testing
environment first, either on a snapshot of your production environment or on a
subset of your live data. Make sure you have back ups configured on your
production environment and a recovery strategy in place in case things go badly.
#### Running the task in the browser
Running the file migration task in the browser should only be considered if you
have a small number of files. It is susceptible to timeout if the task runs for
too long. Depending on your application settings, you may not have the output
logs of the tasks run. Please consider the other options first.
To run the task in the browser, navigate to `/dev/tasks/MigrateFileTask` and
provide the `only` parameter as a GET parameter on your request. e.g.:
`https://example.com/dev/tasks/MigrateFileTask?only=migrate-folders`
If you're running this task on a production environment, you will be asked to
login using administrator credentials and you will be prompted to confirm you
want to execute the task.
#### Running the task on the command line
Navigate to your project root on the command line and use the sake utility to
execute the `MigrateFileTask` command.
```bash
./vendor/bin/sake dev/tasks/MigrateFileTask only=migrate-folders
```
[Learn how to execute Silverstripe CMS tasks on the command line](https://docs.silverstripe.org/en/4/developer_guides/cli/)
#### Running the task as a queued job
If you've installed the
[queued-jobs module](https://github.com/symbiote/silverstripe-queuedjobs) on
your Silverstripe CMS project, you can run the file migration task as a queued
job. There are two alternative ways to schedule a task to run as a queued job:
* by navigating to the task URL in your browser (e.g.:
`https://example.com/dev/tasks/queue/MigrateFileTask?only=migrate-folders`)
* via the command line (e.g.
`vendor/bin/sake dev/tasks/queue/MigrateFileTask only=migrate-folders`).
Once the task has been scheduled, you can monitor its progress in the queued job
administration area inside the CMS.
### How long should I expect the migration tasks to run for?
#### migrate-folders
The main factor in the execution time of the `migrate-folders` subtask is the
number of Folders to migrate.
This subtask does not perform any filesystem operations. It mostly performs read
and write SQL queries.
You can expect 20 to 30 Folders to be migrated per second. A project with
10,000 Folders to migrate should take less than 10 minutes.
#### normalise-access
The main factor in the execution time of the `normalise-access` subtask are:
* the number of files to protect
* the number of files in the same folder.
Protecting 1000 folders with 1 file each will be considerably faster than 1
folder with 1000 files. The total number of files in your project will also
impact the subtask runtime, but to a lesser extent.
This substask performs a lot of file system operations with some read SQL
queries. It does not write data to the database.
You can expect 10 to 20 files to be protected per seconds. Performance is
degraded if all those files are in a small number of folders.
* A project with 10,000 files to protected spread through a lot of folders
should take less than an hour.
* A project with 10,000 files to protected all in one folder can take several
hours.
#### relocate-userform-uploads-2020-9280
The main factor in the execution time of the `normalise-access` subtask are:
* the number of files to protect
* the number of files in the same folder.
Moving 1000 folders with 1 file each will be considerably faster than 1 folder
with 1000 files.
This substask performs a mix of file system operations and read/write SQL
queries.
The approximate speed of the task is:
- 500 files per minute with 1k files in the same folder (9 files per second)
- 60 files per minute with 10k files in the same folder (1 file per second).
## Edges cases and potential "gotchas"
### I don't have "/Uploads" folder in CMS
Either the default "Uploads" folder was changed via
[Silverstripe\Assets\Upload::uploads_folder](https://api.silverstripe.org/4/SilverStripe/Assets/Upload.html)
configuration parameter, or you don't have any files uploaded to it.
The issues covered by this patch may still affect your application.
### I have two "/Uploads" folders in CMS
If you see two /Uploads folders in CMS, most likely that means one of them was
migrated from Silverstripe CMS 3, whereas some application logic created the
second copy after the migration.
In that case your database would contain a record in the `File` table for each
of them, while `File_Live` table would only have a record about the other one.
After running the tasks provided in this patch, we suggest you manually move all
content from one Folder to the other via the CMS. Then remove the empty folder.
### What if I updated my files after upload?
Beware that draft files are present in 2 locations on the filesystem.
* The original live version of the file is still available.
* The draft version of the file should be present in a `.protected` folder that
is inaccessible for unauthenticated users.
This means that even if you moved a file but don't publish it, the live version
of the file will still be available.
To address this, "relocate-userform-uploads-2020-9280" task only works on the
very first version of a file if it's published. Subsequent versions of the file
are ignored by the task. For example, even if you didn't change the location of
a file, but updated the filename or its permissions, the script will ignore that
file.
If you have an unpublished draft, but the live version of the file is 1 (no
published changes after upload), the script will try to move the live version of
the file into its originally intended location, while preserving the current
draft version of the file as-is. This would increment numbers for both Live and
Draft versions of the file, while moving the live version to another location
(both on the file system and in the CMS).
### Files with draft access restriction
If you have a published file that is publicly available and you update the draft
version to restrict read access, the live file currently remains accessible
until you publish the draft version. However, the `canView` method on the live
file will immediately start returning `false` for anonymous users.
This will cause `normalise-access` to protect the live file. Beware that if
you have unpublished access restrictions on draft files, those will take effect
on the live file after running `normalise-access`.
Read the ["Files with access restriction in Draft" GitHub issue](https://github.com/silverstripe/silverstripe-assets/issues/385)
for more details.
<!--- Changes below this line will be automatically regenerated -->
<!--- Changes above this line will be automatically regenerated -->