Skip to content

Commit

Permalink
DOC Document using symfony/validator logic (#590)
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli authored Oct 2, 2024
1 parent 2cc7091 commit 97d473e
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 22 deletions.
55 changes: 34 additions & 21 deletions en/02_Developer_Guides/09_Security/05_Secure_Coding.md
Original file line number Diff line number Diff line change
Expand Up @@ -578,47 +578,60 @@ 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
---
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:

Expand Down
50 changes: 49 additions & 1 deletion en/08_Changelogs/6.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,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)
Expand All @@ -29,6 +30,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
Expand Down Expand Up @@ -450,12 +452,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

Expand Down Expand Up @@ -657,6 +701,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}

<!--- Changes below this line will be automatically regenerated -->
Expand Down

0 comments on commit 97d473e

Please sign in to comment.