mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
449 lines
20 KiB
Markdown
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 -->
|