亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

php Session的工作機制詳解

發布時間:2021-09-10 17:44:49 來源:億速云 閱讀:123 作者:chen 欄目:開發技術

本篇內容主要講解“php Session的工作機制詳解”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“php Session的工作機制詳解”吧!

一、HTTP無狀態性

Http是一種無狀態性的協議。這是因為此種協議不要求瀏覽器在每次請求中標明它自己的身份,并且瀏覽器以及服務器之間并沒有保持一個持久性的連接用于多個頁面之間的訪問。當一個用戶訪問一個站點的時候,用戶的瀏覽器發送一個http請求到服務器,服務器返回給瀏覽器一個http響應。其實很簡單的一個概念,客戶端一個請求,服務器端一個回復,這就是整個基于http協議的通訊過程。
因為web應用程序是基于http協議進行通訊的,而我們已經講過了http是無狀態的,這就增加了維護web應用程序狀態的難度, 對于開發者來說,是一個不小的挑戰。Cookies是作為http的一個擴展誕生的,其主要用途是彌補http的無狀態特性,提供了一種保持客戶端與服務器端之間狀態的途徑,但是由于出于安全性的考慮,有的用戶在瀏覽器中是禁止掉cookie的。這種情況下,狀態信息只能通過url中的參數來傳遞到服務器端,不過這種方式的安全性很差。事實上,按照通常的想法,應該有客戶端來表明自己的身份,從而和服務器之間維持一種狀態,但是出于安全性方面的考慮,我們都應該明白一點 – 來自客戶端的信息都是不能完全信任的。
盡管這樣,針對維持web應用程序狀態的問題,相對來說,還是有比較優雅的解決方案的。不過,應該說是沒有完美的解決方案的,再好的解決方案也不可能適用所有的情況。這篇文章將介紹一些技術。這些技術可以用來比較穩定地維持應用程序的狀態以及抵御一些針對session的攻擊,比如會話劫持。并且你可以學習到cookie是怎樣工作的,php 的session做了那些事情,以及怎樣才能劫持session。

二、http 概覽

如何才能保持web應用程序的狀態以及選擇最合適的解決方案呢?在回答這個問題之前,必須得先了解web的底層協議 – Hypertext Transfer Protocol (HTTP)。

當用戶訪問http://example.com這個域名的時候,瀏覽器就會自動和服務器建立tcp/ip連接,然后發送http請求到example.com的服務器的80端口。該個請求的語法如下所示:

復制代碼 代碼如下:

   
        GET / HTTP/1.1
        Host: example.org

以上第一行叫做請求行,第二個參數(一個反斜線在這個例子中)表示所請求資源的路徑。反斜線代表了根目錄;服務器會轉換這個根目錄為服務器文件系統中的一個具體目錄。
Apache的用戶常用DocumentRoot這個命令來設置這個文檔根路徑。如果請求的url是http://example.org/path/to/script.php,那么請求的路徑就是/path/to/script.php。假如document root 被定義為usr/lcoal/apache/htdocs的話,整個請求的資源路徑就是/usr/local/apache/htdocs/path/to/script.php。
第二行描述的是http頭部的語法。在這個例子中的頭部是Host, 它標識了瀏覽器希望獲取資源的域名主機。還有很多其它的請求頭部可以包含在http請求中,比如user-Agent頭部,在php可以通過$_SERVER['HTTP_USER_AGENT']獲取請求中所攜帶的這個頭部信息。
但是遺憾的是,在這個請求例子中,沒有任何信息可以唯一標識當前這個發出請求的客戶端。有些開發者借助請求中的ip頭部來唯一標識發出此次請求的客戶端,但是這種方式存在很多問題。因為,有些用戶是通過代理來訪問的,比如用戶A通過代理B連接網站www.example.com, 服務器端獲取的ip信息是代理B分配給A的ip地址,如果用戶這時斷開代理,然后再次連接代理的話,它的代理ip地址又再次改變,也就說一個用戶對應了多個ip地址,這種情況下,服務器端根據ip地址來標識用戶的話,會認為請求是來自不同的用戶,事實上是同一個用戶。 還用另外一種情況就是,比如很多用戶是在同一個局域網里通過路由連接互聯網,然后都訪問www.example.com的話,由于這些用戶共享同一個外網ip地址,這會導致服務器認為這些用戶是同一個用戶發出的請求,因為他們是來自同一個ip地址的訪問。
保持應用程序狀態的第一步就是要知道如何來唯一地標識每個客戶端。因為只有在http中請求中攜帶的信息才能用來標識客戶端,所以在請求中必須包含某種可以用來標識客戶端唯一身份的信息。Cookie設計出來就是用來解決這一問題的。

三、cookies

如果你把Cookies看成為http協議的一個擴展的話,理解起來就容易的多了,其實本質上cookies就是http的一個擴展。有兩個http頭部是專門負責設置以及發送cookie的,它們分別是Set-Cookie以及Cookie。當服務器返回給客戶端一個http響應信息時,其中如果包含Set-Cookie這個頭部時,意思就是指示客戶端建立一個cookie,并且在后續的http請求中自動發送這個cookie到服務器端,直到這個cookie過期。如果cookie的生存時間是整個會話期間的話,那么瀏覽器會將cookie保存在內存中,瀏覽器關閉時就會自動清除這個cookie。另外一種情況就是保存在客戶端的硬盤中,瀏覽器關閉的話,該cookie也不會被清除,下次打開瀏覽器訪問對應網站時,這個cookie就會自動再次發送到服務器端。一個cookie的設置以及發送過程分為以下四步:

1.客戶端發送一個http請求到服務器端
2.服務器端發送一個http響應到客戶端,其中包含Set-Cookie頭部
3.客戶端發送一個http請求到服務器端,其中包含Cookie頭部
4.服務器端發送一個http響應到客戶端
這個通訊過程也可以用以下下示意圖來描述:

php Session的工作機制詳解
 

在客戶端的第二次請求中包含的Cookie頭部中,提供給了服務器端可以用來唯一標識客戶端身份的信息。這時,服務器端也就可以判斷客戶端是否啟用了cookies。盡管,用戶可能在和應用程序交互的過程中突然禁用cookies的使用,但是,這個情況基本是不太可能發生的,所以可以不加以考慮,這在實踐中也被證明是對的。

四、get and post data

除了cookies,客戶端還可以將發送給服務器的數據包含在請求的url中,比如請求的參數或者請求的路徑中。 我們來看一個例子:

復制代碼 代碼如下:


GET /index.php?foo=bar HTTP/1.1
        Host: example.org

以上就是一個常規的http get 請求,該get請求發送到example.org域名對應的web 服務器下的index.php腳本, 在index.php腳本中,可以通過$_GET['foo']來獲取對應的url中foo參數的值,也就是'bar'。大多數php開發者都稱這樣的數據會GET數據,也有少數稱它為查詢數據或者url變量。但是大家需要注意一點,不是說GET數據就只能包含在HTTP GET類型的請求中,在HTTP POST類型的請求中同樣可以包含GET數據,只要將相關GET數據包含在請求的url中即可,也就是說GET數據的傳遞不依賴與具體請求的類型。

另外一種客戶端傳遞數據到服務器端的方式是將數據包含在http請求的內容區域內。 這種方式需要請求的類型是POST的,看下面一個例子:

復制代碼 代碼如下:

    
       POST /index.php HTTP/1.1
       Host: example.org
       Content-Type: application/x-www-form-urlencoded
       Content-Length: 7

       foo=bar

   
在這種情況下,在腳本index.php可以通過調用$_POST['foo']來獲取對應的值bar。開發者稱這個數據為POST數據,也就是大家熟知的form以post方式提交請求的方式。

在一個請求中,可以同時包含這兩種形式的數據:

復制代碼 代碼如下:

    
        POST /index.php?myget=foo HTTP/1.1
        Host: example.orgContent-Type: application/x-www-form-urlencoded
        Content-Length: 11

        mypost=bar
[code]   
這兩種傳遞數據的方式,比起用cookies來傳遞數據更穩定,因為cookie可能被禁用,但是以GET以及POST方式傳遞數據時,不存在這種情況。我們可以將PHPSESSID包含在http請求的url中,就像下面的例子一樣:
[code]    
        GET /index.php?PHPSESSID=12345 HTTP/1.1
        Host: example.org

   
以這種方式傳遞session id的話,可以跟用cookie頭部傳遞session id一樣,達到同樣的效果, 但是,缺點就是需要開發者認為地將session id附加在url中或者作為隱藏字段加入到表單中。不像cookie一樣,只要服務器端指示客戶端創建cookie成功以后,客戶端在后續的請求中,會自動第將對應的沒有過期的cookie傳遞給服務器端。當然,php在開啟session.use_trans_sid后,也可以自動地將session id 附加在url中以及表單的隱藏字段中,但是這個選項不建議開啟,因為存在安全問題。這樣的話,容易泄露session id, 比如有的用戶會bookmark一個url或者分享一個url,那么session id也就暴露了,加入這個session id還沒有過期,那是有一定的安全問題存在的,除非服務器端,除了session id外,還附加了其它方式進行驗證用戶的合法性!

盡管以POST的方式來傳遞session id的話,相對GET的方式來說,會安全的多。但是,這種方式的缺點就是比較麻煩,因為這樣的話,在你的應用程序中比較將所有的請求都轉換成post的請求,這顯然是不太合適的。

五、session的管理

直到現在,我只討論了如何維護應用程序的狀態,只是簡單地涉及到了如果保持請求之間的關系。接下來,我闡述下在實際中用到比較多的技術 – Session的管理。涉及到session的管理,就不是單單地維持各個請求之間的狀態,還需要維持會話期間針對每個特定用戶使用到的數據。我們常常把這種數據叫做session數據,因為這些數據是跟某個特定用戶與服務器之間的會話相關聯的。如果你使用php內置的session的管理機制,那么session數據一般是保存在/tmp這個服務器端的文件夾中,并且其中的session數據會被自動地保存到超級數組$_SESSION中。一個最簡單的使用session的例子,就是將相關的session數據從一個頁面傳遞(注意:實際傳遞的是session id)到另一個頁面。下面用示例代碼1, start.php, 對這個例子加以演示:

示例代碼1 – start.php

復制代碼 代碼如下:

   
        <!--?php
        session_start();
        $_SESSION['foo'] = 'bar';
        ?-->

        <a href="continue.php">continue.php</a>



假如用戶點擊start.php中的鏈接訪問continue.php,那么在continue.php中就可以通過$_SESSION['foo']獲取在start.php中的定義的值'bar'。看下面的示例代碼2:

示例代碼2 – continue.php

復制代碼 代碼如下:

       <!--?php
        session_start();
        echo $_SESSION['foo']; /* bar */
        ?-->

   
是不是非常簡單,但是我要指出的話,如果你真的這樣來寫代碼的話,說明你對php底層的對于session的實現機制還不是非常了解透徹。在不了解php內部給你自動做了多少事情的情況下,你會發現如果程序出錯的話,這樣的代碼將變的很難調試,事實上,這樣的代碼也完全沒有安全性可言。

六、session的安全性問題

一直以來很多開發者都認為php內置的session管理機制是具有一定的安全性,可以對一般的session攻擊起到防御。事實上,這是一種誤解,php團隊只實現了一種方便有效的機制。具體的安全措施,應該有應用程序的開發團隊來實施。 就像開篇談到的,沒有最好的解決方案,只有最合適你的方案。

現在,我們來看下一個比較常規的針對session的攻擊:

1..用戶訪問http://www.example.org,并且登錄。
2.example.org的服務器設置指示客戶端設置相關cookie – PHPSESSID=12345
3.攻擊者這時訪問http://www.example.org/,并且在請求中攜帶了對應的cookie – PHPSESSID=12345
4.這樣情況下,因為example.orge的服務器通過PHPSESSID來辨認對應的用戶的,所以服務器錯把攻擊者當成了合法的用戶。
整個過程的描述,請看下面的示例圖:

php Session的工作機制詳解
 

當然這種攻擊的方式,前提條件是攻擊者必須通過某種手段固定,劫持或者猜測出某個合法用戶的PHPSESSID。雖然這看起來難度很高,但是也不是不可能的事情。

七、安全性的加強

有很多技術可以用來加強Session的安全性,主要思想就是要使驗證的過程對于合法用戶來說,越簡單越好,然后對于攻擊者來說,步驟要越復雜越好。當然,這似乎是比較難于平衡的,要根據你應用程序的具體設計來做決策。

最簡單的居于HTTP/1.1請求包括請求行以及一些Host的頭部:

復制代碼 代碼如下:

    
        GET / HTTP/1.1
        Host: example.org

   
如果客戶端通過PHPSESSID傳遞相關的session標識符,可以將PHPSESSID放在cookie頭部中進行傳遞:

復制代碼 代碼如下:

    
        GET / HTTP/1.1
        Host: example.org
        Cookie: PHPSESSID=12345

   
同樣地,客戶端也可以將session標識符放在請求的url中進行傳遞。

復制代碼 代碼如下:

    
        GET /?PHPSESSID=12345
        HTTP/1.1Host: example.org

   
當然,session標識符也可以包含在POST數據中,但是這對用戶體驗有影響,所以這種方式很少采用。

因為來自TCP/IP信息也不一定可以完全信任的,所以,對于web開發者來說,利用TCP/IP中的信息來加強安全性也是不太合適的。 不過,攻擊者也必須提供一個合法用戶的唯一的標識符,才能假扮成合法用戶進入系統。因此,看起來唯一能夠有效的保護系統的措施,就是盡量地隱藏session標識符或者使之難于猜測出來。最好就是兩者都能實施。

PHP會自動生成一個隨機的session ID,基本來說是不可能被猜測出來的,所以這方面的安全還是有一定保障的。但是,要防止攻擊者獲取一個合法的session ID是相當困難的,這基本上不是開發者所能控制的。

事實上,許多情況下都有可能導致session ID的泄露。 比如說,如果通過GET數據來傳遞session ID的話,就有可能暴露這個敏感的身份信息。因為,有的用戶可能會將帶有session ID的鏈接緩存,收藏或者發送在郵件內容中。Cookies是一種像相對來說安全一點的機制,但是用戶是可以在客戶端中禁止掉cookies的!在一些IE的版本中也有比較嚴重的安全漏洞,比較有名的就是會泄露cookies給一些有安全隱患的邪惡站點。

因此,作為一個開發者,可以肯定session ID是不能被猜測出來的,但是還是有可能被攻擊者使用某些方法獲取到。所以,必須采取一些額外的安全措施來防止此類情況在你的應用程序中發生。

實際上,一個標準的HTTP請求中除了Host等必須包含的頭部,還包含了一些可選的頭部.舉一個例子,看下面的一個請求:

復制代碼 代碼如下:

   
        GET / HTTP/1.1
        Host: example.org
        Cookie: PHPSESSID=12345
        User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1
        Accept: text/html;q=0.9, */*;q=0.1
        Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66
        Accept-Language: en

   
我們可以看到,在以上的一個請求例子中包含了四個額外的頭部,分別是User-Agent, Accept, Accept-Charset以及Accept-Language。因為這些頭部不是必須的,所以完全依賴他們在你的應用程序中發揮作用是不太明智的。但是,如果一個用戶的瀏覽器確實發送了這些頭部到服務器,那么可以肯定的是在接下來的同一個用戶通過同一個瀏覽器發送的請求中,必然也會攜帶這些頭部。當然,這其中也會有極少數的特殊情況發生。假如以上例子是由一個當前的跟服務器建立了會話的用戶發出的請求,考慮下面的一個請求:

復制代碼 代碼如下:

  
        GET / HTTP/1.1
        Host: example.org
        Cookie: PHPSESSID=12345
        User-Agent: Mozilla/5.0



因為有相同的session id包含在請求的Cookie頭部中,所以相同的php session將會被訪問到。但是,請求里的User-Agent頭部跟先前的請求中的信息是不同的,系統是否可以假定這兩個請求是同一個用戶發出的?

像這種情況下,發現瀏覽器的頭部改變了,但是不能肯定這是否是一次來自攻擊者的請求的話,比較好的措施就是彈出一個要求輸入密碼的輸入框讓用戶輸入,這樣的話,對用戶體驗的影響不會很大,又能很有效地防止攻擊。

當然,你可以在系統中加入核查User-Agent頭部的代碼,類似示例3中的代碼:

示例代碼 3:

復制代碼 代碼如下:

   
        <!--?php
            session_start();

            if (md5($_SERVER['HTTP_USER_AGENT']) != $_SESSION['HTTP_USER_AGENT'])
            {   /* 彈出密碼輸入框 */   exit;
            }

            /* 其它代碼 */
        ?-->

   
當然,你先必須在第一次請求時,初始化session的時候,用MD5算法加密user agent信息并且保存在session中,類似下面示例4中的代碼:

示例代碼 4:

復制代碼 代碼如下:

   
       <!--?php
        session_start();

        $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);

        ?-->

雖然不一定需要用MD5來加密這個User-Agent信息,但使用這種方式以后就不需要再過濾這個$_SERVER['HTTP_USER_AGENT']數據了。不然的話,在使用這個數據以前必須要進行數據過濾,因為任何來自客戶端的數據都是不可信任的,必須要注意這一點。

在你檢查這個User-Agent客戶端頭部信息以后,做為一個攻擊者必須要完成兩步才能劫持一個session:

1.獲取一個合法的session id
2.包含一個相同的User-Agent頭部在偽造的請求中

你可能會說,居然攻擊者能獲得有效的session id,那么以他的水平,偽造一個相同的User-Agent不是件難事。不錯,但是我們可以說這至少給他添加了一些麻煩,在一定程度上也增加了session機制的安全性。

你應該也能想到了,既然我們可以檢查User-Agent這個頭部來加強安全性,那么不妨再利用其它的一些頭部信息,把他們組合起來生成一個加密的token,并且讓客戶端在后續的請求中攜帶這個token!這樣的話,攻擊者基本上不可能猜測出這樣一個token是怎么生成出來的。這好比你用信用卡在超市付款,一個你必須有信用卡(好比session id),另外你也必須輸入一個支付密碼(好比token),這有這兩者都符合的情況下,你才能成功進入賬號付款。 看下面一段代碼:

復制代碼 代碼如下:



       <!--?php
        session_start();

        $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);

        ?-->

   
注意:Accept這個頭部不應該被用來生成token,因為有些瀏覽器會自動改變這個頭部,當用戶刷新瀏覽器的時候。

在你的驗證機制中加入了這個非常難于猜測出來的token以后,安全性會得到很大的提升。假如這個token通過像session id一樣的方式來進行傳遞,這種情況下,一個攻擊者必須完成必要的3步來劫持用戶的session:

1.獲取一個合法的session ID
2.在請求中加入相同的User-Agent頭部,用與生成token
3.在請求中攜帶被攻擊者的token
4.這里面有個問題。如果session id以及token都是通過GET數據來傳遞的話,那么對于能獲取session ID的攻擊者,同樣就能夠獲取到這個token。所以,比較安全靠譜的方式應該是利用兩種不同的數據傳遞方式來分別傳遞session id以及token。例如,通過cookie來傳遞session id,然后通過GET數據來傳遞token。因此,假如攻擊者通過某種手段獲得了這個唯一的用戶身份標識,也是不太可能同時輕松地獲取到這個token,它相對來說依然是安全的。

還有很多的技術手段可以用來加強你的session機制的安全性。希望你在大致了解session的內部本質以后,可以設計出適合你的應用系統的驗證機制,從而大大的提高系統的安全性。畢竟,你是最熟悉當下你開發的系統的開發者之一,可以根據實際情況來實施一些特有的,額外的安全措施。

到此,相信大家對“php Session的工作機制詳解”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汪清县| 馆陶县| 阜新| 鄂托克旗| 微博| 曲水县| 汉阴县| 镇雄县| 永修县| 女性| 黎川县| 昭苏县| 浙江省| 吐鲁番市| 东平县| 玉屏| 涟水县| 安福县| 子洲县| 定州市| 普兰店市| 沭阳县| 潜山县| 广昌县| 石城县| 邓州市| 滕州市| 永嘉县| 温州市| 大同县| 湘西| 鹤山市| 界首市| 平定县| 陆河县| 牡丹江市| 临城县| 绥宁县| 颍上县| 长子县| 古丈县|