security/flags
< >

return function () {
    $docs = _class('docs');
    $intro = '<p class="docs-demo-intro">The opt-in security switches, from the same list as the
        <a href="' . url('/@object/install') . '#harden">Install page</a> (<code>yf_docs::$HARDEN</code>). Each one is off by default so that
        existing sites keep their behaviour; a default changes only in a major release.
        <b>Default</b> is the class property, <b>this site</b> is what the docs site\'s own <code>$PROJECT_CONF</code> sets.
        Details: the <a href="https://github.com/yfix/yf/blob/master/docs/UPGRADING.md">upgrade notes</a> and the API reference of each class.</p>';
    $show = function ($v) {
        return '<code>' . _prepare_html(is_array($v) ? json_encode($v) : var_export($v, true), 0) . '</code>';
    };
    $rows = '';
    foreach ($docs->HARDEN as $name => $info) {
        $flags = [];
        $defaults = [];
        $current = [];
        foreach ($info['flags'] as [$class, $property, $dir]) {
            $v = $docs->_flag_values($class, $property, $dir);
            $flags[] = '<code>' . $class . '.' . $property . '</code>';
            $defaults[] = $v['known'] ? $show($v['default']) : '<span class="text-muted">?</span>';
            // live values (proxy ranges, cookie settings) are not shown to visitors: only whether the site changed the default
            $current[] = $v['known'] ? ($v['current'] === $v['default'] ? '<span class="text-muted">default</span>' : '<b>set</b>') : '<span class="text-muted">?</span>';
        }
        $rows .= '<tr><td><b>' . _prepare_html($info['title'], 0) . '</b>' . $info['note']
            . '<pre class="docs-demo-snippet"><code class="php">' . _prepare_html($info['snippet'], 0) . '</code></pre></td>'
            . '<td>' . implode('<br>', $flags) . '</td><td>' . implode('<br>', $defaults) . '</td><td>' . implode('<br>', $current) . '</td></tr>';
    }
    css('.docs-demo-flags code { white-space:normal; word-break:break-word; }
        pre.docs-demo-snippet { margin:6px 0 0; } pre.docs-demo-snippet code { white-space:pre-wrap; word-break:break-word; }');
    return $intro . '<div class="table-responsive"><table class="table table-bordered table-condensed table-sm docs-demo-flags" style="width:100%">'
        . '<thead><tr><th style="width:55%">Switch and how to turn it on</th><th>Property</th><th>Default</th><th>This site</th></tr></thead><tbody>' . $rows . '</tbody></table></div>';
};

The opt-in security switches, from the same list as the Install page (yf_docs::$HARDEN). Each one is off by default so that existing sites keep their behaviour; a default changes only in a major release. Default is the class property, this site is what the docs site's own $PROJECT_CONF sets. Details: the upgrade notes and the API reference of each class.

Switch and how to turn it onPropertyDefaultThis site
CSRF tokens in the admin (the user side has them already)
$PROJECT_CONF['csrf_guard']['ENABLED_FOR'] = ['admin' => true, 'user' => true];
csrf_guard.ENABLED_FOR{"admin":false,"user":true}default
Session cookie: SameSite, HTTPS only
$PROJECT_CONF['session']['COOKIE_SAMESITE'] = 'Lax';
$PROJECT_CONF['session']['COOKIE_SECURE'] = true;
session.COOKIE_SAMESITE
session.COOKIE_SECURE
'None'
false
default
default
Session strict mode: unknown session ids are replaced
$PROJECT_CONF['session']['USE_STRICT_MODE'] = true;
session.USE_STRICT_MODEfalsedefault
Passwords: bcrypt (or argon2id), old hashes re-hashed on login. Widen user.password to VARCHAR(255) first
$PROJECT_CONF['password']['ALGO'] = 'bcrypt';
$PROJECT_CONF['password']['HASH_ON_WRITE'] = true;
$PROJECT_CONF['password']['REHASH_ON_LOGIN'] = true;
password.ALGO
password.HASH_ON_WRITE
password.REHASH_ON_LOGIN
'sha256'
false
false
default
default
default
Encryption: sodium with a per-install key
define('YF_SECRET_KEY', '<32+ random bytes, per install>');
$PROJECT_CONF['encryption']['DRIVER'] = 'sodium';
encryption.DRIVER'cast'default
Remember-me tokens instead of a password-derived cookie
$PROJECT_CONF['auth_user']['REMEMBER_ME_TOKENS'] = true;
auth_user.REMEMBER_ME_TOKENSfalsedefault
Error pages: 500 / 404 / 403 with the status code
$PROJECT_CONF['core_errors']['ERROR_PAGES'] = true;
core_errors.ERROR_PAGESfalsedefault
Secrets in error logs: passwords, tokens, card fields and session ids masked in the logged request
$PROJECT_CONF['core_errors']['LOG_REDACT'] = true;
core_errors.LOG_REDACTfalsedefault
Query builder escapes values. On an existing site run make audit-double-escape SITE=... first
$PROJECT_CONF['db']['ESCAPE_BUILDER_VALUES'] = true;
db.ESCAPE_BUILDER_VALUESfalsedefault
Template auto-escaping ({var|raw} for HTML values)
$PROJECT_CONF['tpl']['AUTO_ESCAPE'] = true;
$PROJECT_CONF['tpl']['EXPOSE_SUPERGLOBALS'] = false;
tpl.AUTO_ESCAPE
tpl.EXPOSE_SUPERGLOBALS
false
true
default
default
Behind a proxy: trust X-Forwarded-For only from it
$PROJECT_CONF['client_utils']['TRUSTED_PROXIES'] = ['10.0.0.0/8'];
client_utils.TRUSTED_PROXIES[]default
Redirects only to your own hosts
$CONF['DOMAINS'] = ['example.com', 'www.example.com'];
$PROJECT_CONF['redirect']['RESTRICT_HOSTS'] = true;
redirect.RESTRICT_HOSTSfalsedefault