# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ---------------------------------------- # # Usage: Call session_start_protected at the beginning of your script, # and call session_write_close_protected at the end. # # Security notes: # 1. This might not protect you if you use register_globals. # 2. This does not protect against PHP vulnerabilities. # 3. This does not protect against programs that have access to your key. # 4. This does not protect you if you do something stupid. require_once "hmac_sha1.php"; function session_start_protected($key) { if (!isset($key)) { die("key must be set"); } if (strlen($key) < 20) { die("key must be at least 20 bytes, preferrably much longer"); } @session_start(); $s_cookie_params = session_get_cookie_params(); $s_id = session_id(); $s_name = session_name(); $s_host = $_SERVER['HTTP_HOST']; $stored_hash = $_SESSION["session_protect__hash_$s_id"]; $stored_data = $_SESSION["session_protect__data_$s_id"]; unset($_SESSION["session_protect__hash_$s_id"]); unset($_SESSION["session_protect__data_$s_id"]); if (isset($stored_hash) and isset($stored_data)) { $real_hash = hmac_sha1($stored_data, $key); } else { $real_hash = null; } if (!is_null($real_hash) and ($real_hash === $stored_hash)) { # The hash is valid. However, we must check that the other data is correct. $package = unserialize($stored_data); unset($stored_data); if (($package['proto'] === 'PHPSessionProtect/0.0') and ($package['id'] === $s_id) and ($package['name'] === $s_name) and ($package['cookie_params'] === $s_cookie_params) and ($package['host'] === $s_host) and ($package['expire'] < time())) { # The metadata is valid. Load the authenticated session data. foreach(array_keys($_SESSION) as $k) { unset($_SESSION[$k]); } session_decode($package['session_data']); return; } } # Session data is invalid or unprotected. Start a new session. session_destroy(); foreach(array_keys($_SESSION) as $k) { unset($_SESSION[$k]); } session_regenerate_id(); session_start(); return; } function session_write_close_protected($key) { if (!isset($key)) { die("key must be set"); } if (strlen($key) < 20) { die("key must be at least 20 bytes, preferrably much longer"); } $s_cookie_params = session_get_cookie_params(); $s_id = session_id(); $s_name = session_name(); $s_expire = time() + $s_cookie_params['lifetime']; $s_host = $_SERVER['HTTP_HOST']; unset($_SESSION["session_protect__hash_$s_id"]); unset($_SESSION["session_protect__data_$s_id"]); ksort($_SESSION); $package = array( 'proto' => 'PHPSessionProtect/0.0', 'id' => $s_id, 'name' => $s_name, 'expire' => $s_expire, 'cookie_params' => $s_cookie_params, 'host' => $s_host, 'session_data' => session_encode()); ksort($package); $package_data = serialize($package); $hash = hmac_sha1($package_data, $key); $_SESSION["session_protect__hash_$s_id"] = $hash; $_SESSION["session_protect__data_$s_id"] = $package_data; session_write_close(); }