Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:73150 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 51361 invoked from network); 14 Mar 2014 09:38:20 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 14 Mar 2014 09:38:20 -0000 Authentication-Results: pb1.pair.com smtp.mail=yohgaki@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=yohgaki@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.215.51 as permitted sender) X-PHP-List-Original-Sender: yohgaki@gmail.com X-Host-Fingerprint: 209.85.215.51 mail-la0-f51.google.com Received: from [209.85.215.51] ([209.85.215.51:49811] helo=mail-la0-f51.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 5C/72-47923-A0EC2235 for ; Fri, 14 Mar 2014 04:38:19 -0500 Received: by mail-la0-f51.google.com with SMTP id c6so1261327lan.38 for ; Fri, 14 Mar 2014 02:38:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc:content-type; bh=kYZ5oC3040Szz5pbxXN9lYv7BFy6IPfXTrBsSG0tFKo=; b=T4wh4UZtwvhZum1toxY22qkV5WB8pAe6W2lPjeBQ9dmvbSqtWXieZBkjXdRzO65N0c Wx3M9pwDCt+FngzPv2t+N4/RW73ofq/u1hqD7B1/KzICa0i0BNLAbPwff8yC8aH27vHm NPomenDFbLofsUsjWwtuv00U63kENQc5g30ZHSYvA3bTHVCQXxbAc5Ogcqt1pV+kDguO 9FsIa6wYU5Qj1enFnZwq9omBHbtpvDVPEuyMcsDtwJckPiZyyLvA2oGkCi/H//NCx390 pHwWGCa1+FHUjFKqbiEbda7sNyzJLJKMREL5CpSFB6d9lXcilzg3PO4HuyMv4CdiHa5o Gwkw== X-Received: by 10.112.164.5 with SMTP id ym5mr315490lbb.48.1394789895677; Fri, 14 Mar 2014 02:38:15 -0700 (PDT) MIME-Version: 1.0 Sender: yohgaki@gmail.com Received: by 10.112.205.73 with HTTP; Fri, 14 Mar 2014 02:37:35 -0700 (PDT) In-Reply-To: <20140314074112.GB26909@mail> References: <20140314074112.GB26909@mail> Date: Fri, 14 Mar 2014 18:37:35 +0900 X-Google-Sender-Auth: LiC0rdaclUvf23hw45dsFnpXn8w Message-ID: To: Mateusz Kocielski Cc: "internals@lists.php.net" Content-Type: multipart/alternative; boundary=001a11c2681844ac1904f48dd462 Subject: Re: [PHP-DEV] Solution for session_regenerate_id() issues From: yohgaki@ohgaki.net (Yasuo Ohgaki) --001a11c2681844ac1904f48dd462 Content-Type: text/plain; charset=UTF-8 Hi Mateusz, On Fri, Mar 14, 2014 at 4:41 PM, Mateusz Kocielski wrote: > I'm not sure if we should handle that in PHP, application usually > regenerates > session on important events (i.e. on user login/logout etc.), so any > requests > with old session should be denied, and this can be achieved using > session_regenerate_id(TRUE). Wouldn't it be better to write a security > note in the documentation rather than making whole thing more complex? > The issue is that session_regenerate_id(TRUE) is unreliable. It could cause race condition since requests from client are not synchronized. There is no way to force synchronized access resources to clients. Out of sync issue would be more noticeable under mobile environment, networks with poor congestion control and/or the same web app in multiple tabs. Users may set timeout flag in $_SESSION array and check the value if session could be active or not. In order to do that in user land, one may do session_start() // ** check timeout flag ** if (!empty($_SESSION['VALID_UNTIL']) && $_SESSION['VALID_UNTIL'] < time()) { session_destroy(); trigger_error('Possible session hijack attack detected'); die('Possible session hijack attack detected'); } // ** set timeout flag ** if ($_SESSION['LAST_REGENERATE'] < time() + 600) { $_SESSION['VALID_UNTIL'] = time() + 60; // Shorter is better, but rather large value is set for lost radio/hand over/etc. Old session is allowed to use as valid session for 60 seconds. session_commit(); // Need to save above data in old session. session_start(); $_SESSION['LAST_REGENERATE'] = time(); // Update regenerate time here. session_regenerate_id(); // New session ID and old session data with old session ID is left unset($_SESSION['VALID_UNTIL']; // This session should not be deleted later. } Something like this should be done for reliable session_regenerate_id(). I think not many apps do this. Above example is allowing 60 seconds window for legitimate user and attacker. If session is hijacked, - User could know attack if session ID is regenerated by attacker. - Attacker could know there is hijack protection if session ID is regenerated by user. Without code like above, both attacker and user may use the session as long as web app allows. User has no chance to know if he/she is under session hijack attack or not. Attacker feels safe to enjoy stolen session. This should be session manager task and calling session_regenerate_id() should be enough for PHP users, IMO. I didn't include automatic session ID regeneration in the RFC, but it could be handled by session manager also. It's just a matter of storing/checking last regenerate time. If users are following security best practices, they should renew session ID periodically even when HTTPS is used. Regards, -- Yasuo Ohgaki yohgaki@ohgaki.net --001a11c2681844ac1904f48dd462--