From ed30173291162fddb7ebe2950528a1e41711f46a Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Thu, 26 Sep 2024 11:51:53 +1200 Subject: [PATCH] DOC Document using symfony/validator logic --- .../09_Security/05_Secure_Coding.md | 55 ++++++++++++------- en/08_Changelogs/6.0.0.md | 50 ++++++++++++++++- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/en/02_Developer_Guides/09_Security/05_Secure_Coding.md b/en/02_Developer_Guides/09_Security/05_Secure_Coding.md index 0c28743d..24e98121 100644 --- a/en/02_Developer_Guides/09_Security/05_Secure_Coding.md +++ b/en/02_Developer_Guides/09_Security/05_Secure_Coding.md @@ -578,13 +578,29 @@ salt values generated with the strongest entropy generators available on the pla (see [RandomGenerator](api:SilverStripe\Security\RandomGenerator)). This prevents brute force attacks with [Rainbow tables](https://en.wikipedia.org/wiki/Rainbow_table). -Strong passwords are a crucial part of any system security. So in addition to storing the password in a secure fashion, -you can also enforce specific password policies by configuring a -[PasswordValidator](api:SilverStripe\Security\PasswordValidator). This can be done through a `_config.php` file -at runtime, or via YAML configuration. +Strong passwords are a crucial part of any system security. -The default password validation rules are configured in the framework's `passwords.yml` -file. You will need to ensure that your config file is processed after it. +The default password validator uses the [`PasswordStrength` constraint](https://symfony.com/doc/current/reference/constraints/PasswordStrength.html) in `symfony/validator`, which determines a password's strength based on its level of entropy. + +You can change the required strength of valid passwords by setting the [`EntropyPasswordValidator.password_strength`](api:SilverStripe\Security\Validation\EntropyPasswordValidator->password_strength) configuration property to one of the valid [minScore values](https://symfony.com/doc/current/reference/constraints/PasswordStrength.html#minscore): + +```yml +SilverStripe\Security\Validation\EntropyPasswordValidator: + password_strength: 4 +``` + +You can also enforce that passwords are not repeated by setting the [`PasswordValidator.historic_count`](api:SilverStripe\Security\Validation\PasswordValidator->historic_count) configuration property: + +```yml +SilverStripe\Security\Validation\PasswordValidator: + historic_count: 6 +``` + +The above example will check that the password wasn't used within the previous 6 passwords set for the member. + +### Rule-based password validation + +If you want more finegrained control over exactly how a "strong" password is determined, you can use the [`RulesPasswordValidator`](api:SilverStripe\Security\Validation\RulesPasswordValidator) which uses an array of regular expressions to validate a password. You can swap to using that validator and configure its options with YAML configuration: ```yml --- @@ -592,33 +608,30 @@ Name: mypasswords After: '#corepasswords' --- SilverStripe\Core\Injector\Injector: - SilverStripe\Security\PasswordValidator: - properties: - MinLength: 7 - HistoricCount: 6 - MinTestScore: 3 + SilverStripe\Security\Validation\PasswordValidator: + class: 'SilverStripe\Security\Validation\RulesPasswordValidator' -# In the case someone uses `new PasswordValidator` instead of Injector, provide some safe defaults through config. -SilverStripe\Security\PasswordValidator: +SilverStripe\Security\Validation\RulesPasswordValidator: min_length: 7 - historic_count: 6 min_test_score: 3 ``` -### Configuring custom password validator tests +> [!NOTE] +> The [`PasswordValidator.historic_count`](api:SilverStripe\Security\Validation\PasswordValidator->historic_count) configuration property also applies to the `RulesPasswordValidator`. -The default password validation character strength tests can be seen in the `PasswordValidator.character_strength_tests` -configuration property. You can add your own with YAML config, by providing a name for it and a regex pattern to match: +You can also add additional regular expression tests to the validator: ```yml -SilverStripe\Security\PasswordValidator: +SilverStripe\Security\Validation\RulesPasswordValidator: character_strength_tests: - contains_secret_word: '/1337pw/' + at-least-three-special-chars: '/[\(\)\&\^\%\$\#\@\!]{3,}/' ``` -This will ensure that a password contains `1337pw` somewhere in the string before validation will succeed. +The above example requires at least 3 of the characters `()&^%$#@!` to be included in the password. + +Note that the [`RulesPasswordValidator.min_test_score`](api:SilverStripe\Security\Validation\RulesPasswordValidator->min_test_score) configuration property determines how many of the regular expression tests must pass for a password to be valid. If the test score is lower than the number of tests you have, the password *doesn't* have to match all of them to be valid. -### Other options +### More password security options In addition, you can tighten password security with the following configuration settings: diff --git a/en/08_Changelogs/6.0.0.md b/en/08_Changelogs/6.0.0.md index ef089250..2c19c008 100644 --- a/en/08_Changelogs/6.0.0.md +++ b/en/08_Changelogs/6.0.0.md @@ -12,6 +12,7 @@ title: 6.0.0 (unreleased) - [Changes to scaffolded form fields](#scaffolded-fields) - [`SiteTree` uses form field scaffolding](#sitetree-scaffolding) - [Changes to the templating/view layer](#view-layer) + - [Changes to password validation](#password-validation) - [Other new features](#other-new-features) - [Dependency changes](#dependency-changes) - [`intervention/image` has been upgraded from v2 to v3](#intervention-image) @@ -28,6 +29,7 @@ title: 6.0.0 (unreleased) - [Other changes](#other-changes) - [MySQL 5 no longer supported](#mysql-5-support) - [`DBDecimal` default value](#dbdecimal-default-value) + - [`RedirectorPage` validation](#redirectorpage-validation) - [Full list of removed and changed API (by module, alphabetically)](#api-removed-and-changed) ## Features and enhancements @@ -209,12 +211,54 @@ The one change we specifically want to call out is for [`ModelData::obj()`](api: See the [full list of removed and changed API](#api-removed-and-changed) to see all of the API with updated typing. -### Other new features and small changes {#other-new-features} +### Changes to password validation {#password-validation} + +#### `PasswordValidator` changes + +The deprecated `SilverStripe\Security\PasswordValidator` class has been renamed to [`RulesPasswordValidator`](api:SilverStripe\Security\Validation\RulesPasswordValidator) and is now optional. + +The default password validator is now [`EntropyPasswordValidator`](api:SilverStripe\Security\Validation\EntropyPasswordValidator) which is powered by the [`PasswordStrength` constraint](https://symfony.com/doc/current/reference/constraints/PasswordStrength.html) in `symfony/validator`. This constraint determines if a password is strong enough based on its entropy, rather than on arbitrary rules about what characters it contains. + +You can change the required strength of valid passwords by setting the [`EntropyPasswordValidator.password_strength`](api:SilverStripe\Security\Validation\EntropyPasswordValidator->password_strength) configuration property to one of the valid [minScore values](https://symfony.com/doc/current/reference/constraints/PasswordStrength.html#minscore): + +```yml +SilverStripe\Security\Validation\EntropyPasswordValidator: + password_strength: 4 +``` + +`EntropyPasswordValidator` also has the same options for avoiding repeate uses of the same password that `RulesPasswordValidator` has. + +This does not retroactively affect existing passwords, but will affect any new passwords (e.g. new members or changing the password of an existing member). + +If you want to revert to the validator that was used in CMS 5, you can do so with this YAML configuration: + +```yml +--- +After: '#corepasswords' +--- +SilverStripe\Core\Injector\Injector: + SilverStripe\Security\Validation\PasswordValidator: + class: 'SilverStripe\Security\Validation\RulesPasswordValidator' +``` + +See [passwords](/developer_guides/security/secure_coding/#passwords) for more information about password validation. + +#### `ConfirmedPasswordField` changes + +If [ConfirmedPasswordField->requireStrongPassword](api:SilverStripe\Forms\ConfirmedPasswordField->requireStrongPassword) is set to true, the old behaviour was to validate that at least one digit and one alphanumeric character was included. This meant that you could have a password like "a1" and it would be considered "strong". + +This has been changed to use the [`PasswordStrength` constraint](https://symfony.com/doc/current/reference/constraints/PasswordStrength.html) in `symfony/validator` instead. Now a password is considered "strong" based on its level of entropy. + +You can change the level of entropy required by passing one of the valid [minScore values](https://symfony.com/doc/current/reference/constraints/PasswordStrength.html#minscore) into [`api:SilverStripe\Forms\ConfirmedPasswordField::setMinPasswordStrength()`](ConfirmedPasswordField::setMinPasswordStrength()). + +### Other new features - Native indexed PHP arrays can now be passed into templates and iterated over with `<% loop $MyArray %>`. Under the hood they are wrapped in [`ArrayList`](api:SilverStripe\Model\List\ArrayList), so you can get the count using `$Count` and use `<% if $ArrayList %>` as a shortcut for `<% if $ArrayList.Count %>`. Other functionality from `ArrayList` such as filtering and sorting cannot be used on arrays since they don't have keys to filter or sort against. - Modules no longer need to have a root level `_config.php` or `_config` directory to be recognised as a Silverstripe CMS module. They will now be recognised as a module if they have a `composer.json` file with a `type` of `silverstripe-vendormodule` or `silverstripe-theme`. - A new [`DataObject::getCMSEditLink()`](api:SilverStripe\ORM\DataObject::getCMSEditLink()) method has been added, which returns `null` by default. This provides more consistency for that method which has previously been inconsistently applied to various subclasses of `DataObject`. See [managing records](/developer_guides/model/managing_records/#getting-an-edit-link) for more details about providing sane values for this method in your own subclasses. - The `CMSEditLink()` method on many `DataObject` subclasses has been renamed to `getCMSEditLink()`. +- The [`UrlField`](api:SilverStripe\Forms\UrlField) class has some new API for setting which protocols are allowed for valid URLs. +- The [`EmailField`](api:SilverStripe\Forms\EmailField) class now uses `symfony/validator` to handle its validation logic, where previously this was validated with a custom regex. ## Dependency changes @@ -416,6 +460,10 @@ MySQL 5.6 and 5.7 are no longer supported. The minimum supported version is MySQ Previously if an invalid default value was provided for a [`DBDecimal`](api:SilverStripe\ORM\FieldType\DBDecimal) database column, it would silently set the defalt value to `0`. This will now throw an exception instead, so that you're aware your configured value is invalid and can correct it. +## `RedirectorPage` validation + +[`RedirectorPage`](api:SilverStripe\CMS\Model\RedirectorPage) now uses the [`Url` constraint](https://symfony.com/doc/current/reference/constraints/Url.html) from `symfony/validator` to validate the `ExternalURL` field. It will no longer add `http://` to the start of URLs for you if you're missing a protocol - instead, a validation error message will be displayed. + ### Full list of removed and changed API (by module, alphabetically) {#api-removed-and-changed}