php / php/php-src

Block premature access to session storage

オープン
#21,115 コメント 7 件 リアクション 1 件 担当者 1 名 GitHub で見る

@Girgias がすでに取り組んでいます。

2026年2月4日 から。

Extension: session Feature Status: Needs Triage
主要言語
C
スター
40.4k
フォーク
8.2k
平均マージ
2日 13時間
マージ済み PR(30日)
96

説明

Description
  • session_start() unconditionally calls SessionHandler::read() - even in cases where the session id has been newly generated just a couple of lines earlier.
  • session_write_close() unconditionally calls SessionHandler::write() even if the session id has been newly generated for the current request and the session is empty.
  • session_regenerate_id(true) unconditionally calls SessionHandler::destroy() even if the session id has been newly generated for the current request.

I think there is some room for optimization if the session module could suppress calls into the session handler in certain situations. I guess its best expressed as phpt what I'm having in mind.


Incoming requests without a session (cookie) shouldn't be accessing storage at all:

--TEST--
Request without session
--EXTENSIONS--
session
--INI--
session.use_strict_mode=1
--FILE--
<?php
error_reporting(E_ALL);
ob_start();

class handler implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
    function open($save_path, $session_name): bool
    {
        print "OPEN: $session_name\n";
        return true;
    }

    function close(): bool
    {
        print "CLOSE\n";
        return true;
    }

    function read($key): string|false
    {
        print "READ: $key\n";
        return "";
    }

    function write($key, $val): bool
    {
        print "WRITE: $key, $val\n";
        return true;
    }

    function destroy($key): bool
    {
        print "DESTROY: $key\n";
        return true;
    }

    function updateTimestamp(string $id, string $data): bool {
        print "UPDATE_TIMESTAMP: $id, $data\n";
        return true;
    }

    function validateId(string $id): bool {
        print "VALIDATE_ID: $id\n";
        return false;
    }

    function gc($max_lifetime): int { return 0; }
}

session_set_save_handler(new handler());

session_start();
session_write_close();
?>
--EXPECT--
OPEN: PHPSESSID
CLOSE

This is failing with the following diff:

Running selected tests.
TEST 1/1 [ext/session/tests/user_session_module/request-without-session.phpt]
========DIFF========
     OPEN: PHPSESSID
002+ READ: 78d7fe4a7170fb5a60934db9784d7d63
003+ WRITE: 78d7fe4a7170fb5a60934db9784d7d63,
     CLOSE
========DONE========

When logging in the initial empty session record shouldn't attempted to be destroyed. Also there is no point in attempting to read a session record with the newly generated id:

--TEST--
Request with login
--EXTENSIONS--
session
--INI--
session.use_strict_mode=1
--FILE--
<?php
error_reporting(E_ALL);
ob_start();

class handler implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
    function open($save_path, $session_name): bool
    {
        print "OPEN: $session_name\n";
        return true;
    }

    function close(): bool
    {
        print "CLOSE\n";
        return true;
    }

    function read($key): string|false
    {
        print "READ: $key\n";
        return "user_id|i:42;";
    }

    function write($key, $val): bool
    {
        print "WRITE: $key, $val\n";
        return true;
    }

    function destroy($key): bool
    {
        print "DESTROY: $key\n";
        return true;
    }

    function updateTimestamp(string $id, string $data): bool {
        print "UPDATE_TIMESTAMP: $id, $data\n";
        return true;
    }

    function validateId(string $id): bool {
        print "VALIDATE_ID: $id\n";
        return false;
    }

    function gc($max_lifetime): int { return 0; }
}

session_set_save_handler(new handler());

session_start();
session_regenerate_id(TRUE);
$_SESSION['user_id']=42;
session_write_close();
?>
--EXPECTF--
OPEN: PHPSESSID
CLOSE
OPEN: PHPSESSID
VALIDATE_ID: %s
WRITE: %s %s
CLOSE

This is failing with the following diff:

Running selected tests.
TEST 1/1 [ext/session/tests/user_session_module/request-with-login.phpt]
========DIFF========
     OPEN: PHPSESSID
002+ READ: 9f2306bd1721271b20061dfe45d044a1
003+ DESTROY: 9f2306bd1721271b20061dfe45d044a1
     CLOSE
     OPEN: PHPSESSID
     VALIDATE_ID: a7efc5fb4eca6fd6e44799a6e50e7960
007+ READ: a7efc5fb4eca6fd6e44799a6e50e7960
     WRITE: %s %s
     CLOSE
========DONE========

When logging out the resulting empty session record shouldn't attempted to be read and written:

--TEST--
Request with logout
--EXTENSIONS--
session
--INI--
session.use_strict_mode=1
--FILE--
<?php
error_reporting(E_ALL);
ob_start();

class handler implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
    function open($save_path, $session_name): bool
    {
        print "OPEN: $session_name\n";
        return true;
    }

    function close(): bool
    {
        print "CLOSE\n";
        return true;
    }

    function read($key): string|false
    {
        print "READ: $key\n";
        return "user_id|i:42;";
    }

    function write($key, $val): bool
    {
        print "WRITE: $key, $val\n";
        return true;
    }

    function destroy($key): bool
    {
        print "DESTROY: $key\n";
        return true;
    }

    function updateTimestamp(string $id, string $data): bool {
        print "UPDATE_TIMESTAMP: $id, $data\n";
        return true;
    }

    function validateId(string $id): bool {
        print "VALIDATE_ID: $id\n";
        return $GLOBALS['validId'];
    }

    function gc($max_lifetime): int { return 0; }
}

session_set_save_handler(new handler());

$GLOBALS['validId'] = true;
session_id(session_create_id());
session_start();
$_SESSION = [];
$GLOBALS['validId'] = false;
session_regenerate_id(TRUE);
session_write_close();
?>
--EXPECTF--
OPEN: PHPSESSID
VALIDATE_ID: %s
READ: %s
DESTROY: %s
CLOSE
OPEN: PHPSESSID
VALIDATE_ID: %s
CLOSE

This is failing with the following diff:

Running selected tests.
TEST 1/1 [ext/session/tests/user_session_module/request-with-logout.phpt]
========DIFF========
--
     CLOSE
     OPEN: PHPSESSID
     VALIDATE_ID: %s
008+ READ: 483617bb2349fe2345fcb67b391e7b1d
009+ WRITE: 483617bb2349fe2345fcb67b391e7b1d,
     CLOSE
========DONE========

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。