PHP:如何檢測會話是否已自動過期?

[英]PHP: how to detect if a session has expired automatically?


When a session expiration time is defined, is it possible to call an event listener when it expires?

定義會話到期時間時,是否可以在事件監聽器到期時調用它?

If it is not possible, is it possible to run a cron job to check if a session has expired?

如果不可能,是否可以運行cron作業來檢查會話是否已過期?

NOTE: I'm interested in a server solution. I'm talking about the case there is a session expiration time defined, and the session finishes automatically because that period expired.

注意:我對服務器解決方案感興趣。我在談論定義了會話到期時間的情況,並且會話因為該期限到期而自動結束。

12 个解决方案

#1


10  

is it possible to call an event listener when it expires?

可以在事件監聽器到期時調用它嗎?

The short answer is NO

最簡潔的答案是不

There are a few oddities people tend to ignore about sessions. With the default handler, the session does not expire when gc_maxlifetime ends - this is just the time at which the data becomes eligible for automatic deletion. There is no action by the owner of the session which triggers the subsequent removal of the session - its a side effect of someone else's session.

人們往往會忽略一些關於會話的奇怪之處。使用默認處理程序時,會話在gc_maxlifetime結束時不會過期 - 這只是數據符合自動刪除條件的時間。會話所有者沒有動作會觸發隨后的會話刪除 - 這是其他人會話的副作用。

When session_write_close() is called (either explicitly, or implicitly by the code ending), if the random number generator, tweaked by the relevant gc settings throws the right number then PHP will go looking for data past its TTL and remove it. If you want to trigger an action at this point, then you need to break the default handler and apply your own. That means you not only have to provide a mechanism for identifying and removing sessions but also a way of deciding whether your handler should kick in and how many sessions it should delete - you don't want a runaway process killing your server.

當調用session_write_close()時(顯式或隱式地通過代碼結束),如果隨機數生成器(通過相關gc設置調整)會拋出正確的數字,那么PHP將繼續尋找超過其TTL的數據並將其刪除。如果您想在此時觸發操作,則需要中斷默認處理程序並應用自己的操作。這意味着您不僅需要提供一種識別和刪除會話的機制,還需要一種方法來決定您的處理程序是否應該啟動以及它應該刪除多少個會話 - 您不希望失控的進程殺死您的服務器。

In Ubuntu, session.gc_probability = 0, and it is a cron job which carries out the function of removing stale data files.

在Ubuntu中,session.gc_probability = 0,它是一個執行刪除陳舊數據文件功能的cron作業。

A very important piece of information missing from your question is the reason for deleting the session.

您的問題中缺少的一條非常重要的信息是刪除會話的原因。

If you want to prevent sensitive data from persisting on the filesystem, then a better solution is to encrypt the data using a key stored (only) in another client side cookie. That way you completely eliminate the storage of unprotected data on your server. (note that suhosin's encrypted sessions use a key derived from data about the client and a static key stored on the same host - this is significantly less secure than a randomly generated key). Here's one I prepared earlier.

如果要防止敏感數據在文件系統上持久存在,那么更好的解決方案是使用另一個客戶端cookie中存儲的密鑰(僅)來加密數據。這樣您就可以完全消除服務器上未受保護數據的存儲。 (請注意,suhosin的加密會話使用從客戶端數據派生的密鑰和存儲在同一主機上的靜態密鑰 - 這比隨機生成的密鑰安全性低得多)。這是我之前准備的。

If you merely want to prevent access after the gc_maxlifetime has expired, you should consider a custom session handler which treats a stale session as missing. i.e. it doesn't really logout at expiry, but any subsequent requests can no longer be associated with the session. The security layer in the Stackable session handler examples implements such a control.

如果您只想在gc_maxlifetime過期后阻止訪問,則應考慮將自定義會話處理程序視為缺失的自定義會話處理程序。即它在到期時並未真正注銷,但任何后續請求都不能再與會話相關聯。 Stackable會話處理程序示例中的安全層實現了這樣的控制。

OTOH if you want to use data from within the session in your event listener, then that's a different story - you certainly won't be able to use either Suhosin's or my encryption for the data. But a further complication is that the (default) format for the data is different from that used elsewhere. You need to use session_encode() and session_decode(). The former will only read data from the $_SESSION array so eavesdropping on sessions requires some careful subversion of session_id() and session_start(). session_decode() however will happily convert anything you throw at it.

OTOH如果你想在事件監聽器中使用會話中的數據,那么這是一個不同的故事 - 你肯定無法使用Suhosin或我的加密數據。但更復雜的是,數據的(默認)格式與其他地方使用的格式不同。您需要使用session_encode()和session_decode()。前者只會從$ _SESSION數組中讀取數據,因此對會話的竊聽需要對session_id()和session_start()進行一些小心的顛覆。然而,session_decode()會愉快地轉換你拋出的任何東西。

In recent versions of PHP you can specify a different function pair to use for serialization/deserialization.

在PHP的最新版本中,您可以指定用於序列化/反序列化的不同函數對。

It is vitally important to consider the potential impact of __wakeup() methods when considering a session garbage collector which is going to read the data in the session files. Related to this is a requirement that the process which handles such garbage collection runs under the same uid as the original PHP process which created the session data (otherwise you have a privilege escalation backdoor). But if the session storage substrate is file-based then that would need to be the case anyway.

在考慮將要讀取會話文件中的數據的會話垃圾收集器時,考慮__wakeup()方法的潛在影響至關重要。與此相關的是要求處理此類垃圾收集的進程在與創建會話數據的原始PHP進程相同的uid下運行(否則您具有權限提升后門)。但是,如果會話存儲基板是基於文件的,那么無論如何都需要這樣。

There are implementations of session data deserializer written in languages other than PHP which would provide protection against __wakeup() attacks (try Google) although that might be overkill to solve the problem and they are probably not being actively maintained. If this is a concern then a more appropriate solution might be to use the WDDX (xml) serializer and use a conventional XML parser to read the data back in your GC engine.

會話數據解串器的實現是用PHP以外的語言編寫的,可以防止__wakeup()攻擊(試試谷歌),雖然這可能有點過頭來解決問題並且它們可能沒有被主動維護。如果這是一個問題,那么更合適的解決方案可能是使用WDDX(xml)序列化程序並使用傳統的XML解析器來讀取GC引擎中的數據。

If you are using the native handler for normal reading and writing of the data but want to implement your own garbage collector then you're going to need code to map the session_id to a file path. If you follow the link I gave to the PHP classes above, you'll see pure PHP implementation of several session handlers, including ones which are compatible with the native handler.

如果您使用本機處理程序來正常讀取和寫入數據但想要實現自己的垃圾收集器,那么您將需要代碼將session_id映射到文件路徑。如果您按照我給上面的PHP類的鏈接,您將看到幾個會話處理程序的純PHP實現,包括與本機處理程序兼容的那些。

But I would strongly encourage you to exhaust every other avenue for solving whatever the underlying problem is before choosing to read back session data at the time of deletion.

但是我強烈建議你在選擇在刪除時回讀會話數據之前用盡所有其他途徑解決任何潛在問題。

#2


3  

It sounds like you want to wipe out the session at a given time on the server side. What you will want to do is define your own custom session handler and put the session data in a system you fully control. So, let's say you move your session handling into a database. Now all your session data is fully within your control. Below is an abbreviated custom session handler

聽起來你想要在服務器端的給定時間消滅會話。您要做的是定義自己的自定義會話處理程序,並將會話數據放在您完全控制的系統中。所以,假設您將會話處理移動到數據庫中。現在,您的所有會話數據都完全在您的控制之內。下面是一個縮寫的自定義會話處理程序

class Sessions implements \SessionHandlerInterface {
    /**
     * Write Session Data
     * @param string $id Session ID to delete
     * @param string $data Data to write into the session
     */
    public function write($id, $data) {
        $time = time() + 3600; // 1 hour for the sake of example
        $sql = 'REPLACE INTO your_session_table
                SET session_id = ?,
                    data = ?,
                    expires = ?';
        $this->db->query($sql);
        $prep = $this->db->prepare($sql);
        $prep->bind_param('ssi', $id, $data, $time);
        $prep->execute();
    }
}

What you can do here is you can run your own cleanup script here. Now, I would suggest you use an intermediate memory store (memcached, Redis, etc) so you don't HAVE to load from the DB every time. You'll want to clean that out when you run your cleanup script (i.e pull all the sessions about to expire and remove from cache). But a simple SQL statement here (run on, say, a 5 minute cron job) cleans out sessions on demand

你在這里可以做的是你可以在這里運行自己的清理腳本。現在,我建議您使用中間存儲器(memcached,Redis等),這樣您就不必每次都從DB加載。在運行清理腳本時,您需要清除它(即拉出所有會話即將過期並從緩存中刪除)。但是這里的一個簡單的SQL語句(例如,運行5分鍾的cron作業)可以按需清除會話

 DELETE FROM your_session_table
 WHERE expires < now();

#3


3  

I'm making a couple of assumptions here.

我在這里做了幾個假設。

I'm assuming, for whatever reason, you want to be able to track the expired session cold, that is, no supplementary tracking of session data via a database or a second 'hidden' session that acts as a structure to determine when a pseudo-session has expired and acting appropriately.

我假設,無論出於何種原因,您希望能夠跟蹤過期的會話冷,即,沒有通過數據庫或第二個“隱藏”會話補充跟蹤會話數據,該會話充當確定何時偽的結構 - 激情已經過期並且行動恰當。

I'm also assuming that hack attempts on your session aren't important at this point. Man-in-the-middle and XSS attacks can capture session ID's and plug them into your system and it would be hard to detect.

我還假設你的會話上的黑客攻擊在這一點上並不重要。中間人和XSS攻擊可以捕獲會話ID並將其插入您的系統,並且很難檢測到。

This sort of thing is handled by session cookies in php by default. I'm also assuming that your session identification and session start are also handled by cookies.

這種事情默認由php中的會話cookie處理。我還假設您的會話標識和會話開始也由cookie處理。

There's almost no way of doing this 'live', which is to say, keep a socket open to the server to detect the moment the session expires. PHP was not designed to work that way; the security issues are expansive. As well, if you're allowing someone to access your server remotely through a secure channel, why are you bothering with sessions in the first place?

幾乎沒有辦法做這個'實時',也就是說,保持套接字打開服務器以檢測會話到期的時刻。 PHP不是為那種方式工作而設計的;安全問題是廣泛的。同樣,如果您允許某人通過安全通道遠程訪問您的服務器,為什么您首先要打擾會話?

$sessionCookie = 'myPHPSessCookieName';
$isSessionExpired = false;

if (isset($_COOKIE[$sessionCookie])) {
  // check cookie expiry time to show warnings / near expiry behaviours
} else {
  // handle missing cookie / session
  $isSessionExpired = true;
}

define('SESSION_EXPIRED', $isSessionExpired);    
session_start(['name' => $sessionCookie]);

Checking for the cookie has to happen prior to starting the session otherwise you run the risk of giving yourself a false positive.

檢查cookie必須在開始會話之前進行,否則你可能會給自己一個誤報。

[edit: javascript solution]

[編輯:javascript解決方案]

If you wish to produce a behaviour that simulates a socket, javascript can do this. The client's browser will ping the server with AJAX requests to check the status of their session, and once it detects that it is expired, you can induce a behaviour of your choice. Note: javascript in its current state is fundamentally insecure. All of the data and security related work ought to be done by the server if at all possible.

如果您希望生成模擬套接字的行為,javascript可以執行此操作。客戶端的瀏覽器將使用AJAX請求ping服務器以檢查其會話的狀態,一旦檢測到它已過期,您就可以引發您選擇的行為。注意:javascript在當前狀態下基本上是不安全的。如果可能的話,所有與數據和安全相關的工作都應由服務器完成。

client.php:

<script>
  $(function(){
    var messageElem = $('#selectorForDisplayElementHere');
    var timeoutID = null;

    var checkSession = function(){
      $
        .ajax({/* your ajax params: url, data, dataType, method etc. */})
        .then(function(response){
          messageElem.html(response.html);
          if (response.stop === 1) { 
            clearTimeout(timeoutID);
          }
        });
    };

    var timeoutID = setInterval(checkSession, 5000); // Every 5 seconds
  });
</script>

ajax.php:

$response = ['html' => '', 'stop' => 0];

if (SESSION_EXPIRED) {
  $response ['html'] = '<b>Your session has expired. Please log in again.</b>';
  $response['stop'] = 1;
}

echo(json_encode($response));

This is a very simple handling system that can be readily enhanced with all sorts of functionality. It uses the ubiquitous jQuery library and standard php and html/javascript functionality.

這是一個非常簡單的處理系統,可以通過各種功能輕松增強。它使用無處不在的jQuery庫和標准的php和html / javascript功能。

#4


2  

You could store the connection time somewhere (table,...) so you can see since when the user was connected and do a regular check (cron or service) to see if the date has passed a specific duration (5 minutes,...)

您可以將連接時間存儲在某個地方(表格,...),這樣您就可以看到自用戶何時連接並定期檢查(cron或服務)以查看日期是否已經過了特定的持續時間(5分鍾,... 。)

But if you want to warn the user (loss of document,...) you might want to do a Javascript window.setTimeout on client side.

但是如果你想警告用戶(丟失文件,......)你可能想在客戶端做一個Javascript window.setTimeout。

#5


2  

Set initial session on one page.

在一個頁面上設置初始會話。

example: Login.php

<?php
session_start();
if(...){
   // success
   $_SESSION['logged_time'] = time();
}
?>

now check the session expired or not in another page

現在檢查會話是否已過期或不在另一頁面中

example: Index.php

<?php
   session_start();
   $login_session_duration = 60; // 1 minute 

   if($_SESSION['logged_time']){
      if(((time() - $_SESSION['logged_time']) > $login_session_duration)){ 
         echo 'session expired';
         // session will be exired after 1 minutes
      }else{
         echo 'session alive';
      }
   }
?>

#6


2  

Each time you send http request to server then check the session expiration time. if session is valid do your stuff, other wise redirect where you want.

每次向服務器發送http請求,然后檢查會話到期時間。如果會話有效,請做你的事情,其他明智的重定向你想要的地方。

Or

You can do one thing to save your time. Create a method which checks current session validity and call it in your http request.

你可以做一件事來節省你的時間。創建一個檢查當前會話有效性的方法,並在您的http請求中調用它。

#7


2  

I think what you are looking for may be here: Access active sessions in PHP

我認為您正在尋找的可能是:在PHP中訪問活動會話

Summarized you would have to create your own session handler. That's the server side.

總結一下,您必須創建自己的會話處理程序。這是服務器端。

If you want to add client side alerts you could store the session expiration time limit used in a javascript timer. If there is only x minutes left pop up a message (maybe with a countdown) displaying to the user "Your session will time out in: (show timer here)."

如果要添加客戶端警報,可以存儲javascript計時器中使用的會話到期時間限制。如果只剩下x分鍾,則會彈出一條消息(可能帶有倒計時),向用戶顯示“您的會話將超時:(此處顯示計時器)”。

#8


2  

You can also use this :)

你也可以用這個:)

<? 
session_start();

$time = 3600; // Set expire time with secends.
// Star session here 
if (isset($_SESSION['time']) && (time() - $_SESSION['time']) > $time) {
   // Your Code Here to logout
   header('location: /auth/logout');
   exit();
} else {
  $_SESSION['time'] = time();
 }

#9


1  

Well very simple way to do is

非常簡單的方法是

get current_time

$current_time=time();

get session expire time which is set in ini file.

獲取在ini文件中設置的會話過期時間。

$maxlifetime = ini_get("session.gc_maxlifetime");

Use this value in javascript/query and when time is expire by mannual calculation use a alert to notify user or write script u wish to do.

在javascript / query中使用此值,當時間到期時,通過手動計算使用警報來通知用戶或編寫您希望執行的腳本。

OR

You can store these dates in separate cookie variable:

您可以將這些日期存儲在單獨的cookie變量中:

session_expire=1525357483057

But user can change this variable.

但是用戶可以更改此變量。

#10


0  

Try checking it against session_cache_expire() if it is zero then your session has ended. Would probably have to be implemented on your action handler. This does not set your session on the server, only solves the problem of your clients browser knowing when it will expire, which is serving as your auto detect...

嘗試對session_cache_expire()進行檢查,如果它為零則會話結束。可能必須在您的操作處理程序上實現。這不會在服務器上設置會話,只能解決客戶端瀏覽器知道何時到期的問題,這可以作為您的自動檢測...

http://php.net/manual/en/function.session-cache-expire.php

#11


-1  

We can use the session variable that you have defined.

我們可以使用您定義的會話變量。

if(isset($_SESSION['variable'])){
    //do something
}

example:

if(isset($_SESSION['name'])){
    echo "Session has not expired"; 
}

#12


-1  

What you would do is run a jQuery AJAX request on a timed interval to check if the session is expired and when it does you can send the users to a logout.

你要做的是在一個定時間隔運行一個jQuery AJAX請求來檢查會話是否過期,什么時候你可以發送用戶注銷。

Ajax Code

var checkSession;
function SessionCheck(){
     var str="sessionCheck=true";
     jQuery.ajax({
                   type:"POST",
                   URL:"sessionCheck.php"
                   data: str,
                   success: function(res){
                        if(res==1){
                            //do session expired logic here
                        }
                   }
                });
    }
sessions = setInterval(SessionCheck, 1000); //This will run the SessionCheck function every second

PHP Code

session_start();
$data = $_SESSION["sessionVariable"];
if($data == ''){
    echo "1";
}
else{
    echo "0";
}

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2016/12/15/83d274ef5f26b15a16e3813bbeb6b1db.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com