|
@@ -29,6 +29,18 @@ namespace App\Auth;
|
|
|
*/
|
|
*/
|
|
|
class SessionManager
|
|
class SessionManager
|
|
|
{
|
|
{
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Base name without prefix. The actual cookie name set on the
|
|
|
|
|
+ * response is `cookieName()`, which adds the `__Host-` prefix
|
|
|
|
|
+ * (SEC_REVIEW F57) when the cookie is `Secure` so the browser
|
|
|
|
|
+ * enforces:
|
|
|
|
|
+ * - `Secure` (HTTPS-only),
|
|
|
|
|
+ * - `Path=/` exactly,
|
|
|
|
|
+ * - no `Domain` attribute (host-only, no subdomain cookie
|
|
|
|
|
+ * shadowing).
|
|
|
|
|
+ * The constant remains for callers that want the unprefixed
|
|
|
|
|
+ * brand name (e.g. log messages, doc strings).
|
|
|
|
|
+ */
|
|
|
public const COOKIE_NAME = 'irdb_session';
|
|
public const COOKIE_NAME = 'irdb_session';
|
|
|
|
|
|
|
|
private const KEY_USER = '_user';
|
|
private const KEY_USER = '_user';
|
|
@@ -82,11 +94,28 @@ class SessionManager
|
|
|
'httponly' => true,
|
|
'httponly' => true,
|
|
|
'samesite' => 'Lax',
|
|
'samesite' => 'Lax',
|
|
|
]);
|
|
]);
|
|
|
- session_name(self::COOKIE_NAME);
|
|
|
|
|
|
|
+ session_name($this->cookieName());
|
|
|
session_start();
|
|
session_start();
|
|
|
$this->enforceLifetimes();
|
|
$this->enforceLifetimes();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * SEC_REVIEW F57: prefix the session cookie with `__Host-` when
|
|
|
|
|
+ * we're issuing it `Secure` (production / HTTPS). The prefix is
|
|
|
|
|
+ * a browser-enforced contract that REJECTS the cookie unless:
|
|
|
|
|
+ * - it has `Secure`,
|
|
|
|
|
+ * - `Path=/` exactly,
|
|
|
|
|
+ * - no `Domain` attribute (so a subdomain can't shadow the
|
|
|
|
|
+ * parent-domain session).
|
|
|
|
|
+ * `__Host-` cookies are also rejected over HTTP, so dev mode
|
|
|
|
|
+ * (`secureCookie=false`, `APP_ENV=development`) keeps the
|
|
|
|
|
+ * unprefixed name.
|
|
|
|
|
+ */
|
|
|
|
|
+ public function cookieName(): string
|
|
|
|
|
+ {
|
|
|
|
|
+ return $this->secureCookie ? '__Host-' . self::COOKIE_NAME : self::COOKIE_NAME;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public function regenerateId(): void
|
|
public function regenerateId(): void
|
|
|
{
|
|
{
|
|
|
if (session_status() !== PHP_SESSION_ACTIVE) {
|
|
if (session_status() !== PHP_SESSION_ACTIVE) {
|