Django之cookie

cookie定義及組成

對於Cookie的定義,跟語言沒有關係的,不管Server端用的是Java、Python等後端語言哪一種,涉及到web開發相關知識時候,必須瞭解這方面知識。

定義

Cookie 並不是它的原意“甜餅”的意思, 而是一個保存在客戶機中的簡單的文本文件, 這個文件與特定的 Web 文檔關聯在一起, 保存了該客戶機訪問這個Web 文檔時的信息, 當客戶機再次訪問這個 Web 文檔時這些信息可供該文檔使用。由於“Cookie”具有可以保存在客戶機上的神奇特性, 因此它可以幫助我們實現記錄用戶個人信息的功能, 而這一切都不必使用複雜的CGI等程序 [2] 。
舉例來說, 一個 Web 站點可能會爲每一個訪問者產生一個唯一的ID, 然後以 Cookie 文件的形式保存在每個用戶的機器上。如果使用瀏覽器訪問 Web, 會看到所有保存在硬盤上的 Cookie。在這個文件夾裏每一個文件都是一個由“名/值”對組成的文本文件,另外還有一個文件保存有所有對應的 Web 站點的信息。在這裏的每個 Cookie 文件都是一個簡單而又普通的文本文件。透過文件名, 就可以看到是哪個 Web 站點在機器上放置了Cookie(當然站點信息在文件裏也有保存)

組成:

Cookie是一段不超過4KB的小型文本數據,由一個名稱(Name)、一個值(Value)和其它幾個用於控制Cookie有效期、安全性、使用範圍的可選屬性組成。其中 [3] :
(1)Name/Value:設置Cookie的名稱及相對應的值,對於認證Cookie,Value值包括Web服務器所提供的訪問令牌 [3] 。
(2)Expires屬性:設置Cookie的生存期。有兩種存儲類型的Cookie:會話性與持久性。Expires屬性缺省時,爲會話性Cookie,僅保存在客戶端內存中,並在用戶關閉瀏覽器時失效;持久性Cookie會保存在用戶的硬盤中,直至生存期到或用戶直接在網頁中單擊“註銷”等按鈕結束會話時纔會失效 [3] 。
(3)Path屬性:定義了Web站點上可以訪問該Cookie的目錄 [3] 。
(4)Domain屬性:指定了可以訪問該 Cookie 的 Web 站點或域。Cookie 機制並未遵循嚴格的同源策略,允許一個子域可以設置或獲取其父域的 Cookie。當需要實現單點登錄方案時,Cookie 的上述特性非常有用,然而也增加了 Cookie受攻擊的危險,比如攻擊者可以藉此發動會話定置攻擊。因而,瀏覽器禁止在 Domain 屬性中設置.org、.com 等通用頂級域名、以及在國家及地區頂級域下注冊的二級域名,以減小攻擊發生的範圍 [3] 。
(5)Secure屬性:指定是否使用HTTPS安全協議發送Cookie。使用HTTPS安全協議,可以保護Cookie在瀏覽器和Web服務器間的傳輸過程中不被竊取和篡改。該方法也可用於Web站點的身份鑑別,即在HTTPS的連接建立階段,瀏覽器會檢查Web網站的SSL證書的有效性。但是基於兼容性的原因(比如有些網站使用自簽署的證書)在檢測到SSL證書無效時,瀏覽器並不會立即終止用戶的連接請求,而是顯示安全風險信息,用戶仍可以選擇繼續訪問該站點。由於許多用戶缺乏安全意識,因而仍可能連接到Pharming攻擊所僞造的網站 [3] 。
(6)HTTPOnly 屬性 :用於防止客戶端腳本通過document.cookie屬性訪問Cookie,有助於保護Cookie不被跨站腳本攻擊竊取或篡改。但是,HTTPOnly的應用仍存在侷限性,一些瀏覽器可以阻止客戶端腳本對Cookie的讀操作,但允許寫操作;此外大多數瀏覽器仍允許通過XMLHTTP對象讀取HTTP響應中的Set-Cookie頭

應用

從定義上來理解cookie,可以作爲存儲介質,存儲一些必要的信息在客戶端,當然這些重要的信息是在第一次在服務端設置到cookie裏面,當第二次訪問請求的時候,服務端通過cookie裏面的值來判定是否有一些必要的數據,從而減輕了Server端的訪問壓力,也就是通過cookie來做了驗證的操作。

舉例說明:
模擬用戶登錄進入首頁的操作:cookie裏面存儲用戶username

  • 用戶進入首頁操作,通過cookie來判斷,如果用戶cookie已經存在username,就直接跳轉到index頁面,如果不存在就直接跳轉到login登錄界面
  • 登錄界面的操作,在登錄成功後,存儲username值到cookie裏面,用於下次直接訪問首頁index時判斷是否已經登錄了
    view中的邏輯代碼如下:
user_info = {
    'test': {'pwd': "123123"},
}
def login(request):
    if request.method == "GET":
        return render(request, 'cookie_login.html')
    if request.method == "POST":
        u = request.POST.get('username')
        p = request.POST.get('pwd')
        dic = user_info.get(u)
        if not dic:
            return render(request, 'cookie_login.html')
        if dic['pwd'] == p:
            res = redirect('/cookietest/index/')
            res.set_cookie('username', u)  # 給重定向的url設cookie
            return res
        else:
            return render(request, 'cookie_login.html')
def index(reqeust):
    v = reqeust.COOKIES.get('username')  # 獲取當前已經登錄的用戶
    if not v:  # 如果獲取不到cookie表示沒有登錄
        return redirect('/cookietest/login/')
    return render(reqeust, 'cookie_test_index.html', {'current_user': v})

login和index頁面分別如下:

cookie_login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>cookie_test_login</title>
</head>
<body>
<form action="/cookietest/login/" method="POST">
    <input type="text" name="username" placeholder="用戶名"/>
    <input type="password" name="pwd" placeholder="密碼"/>
    <input type="submit"/>
</form>
</body>
</html>

cookie_test_index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Cookie_test_index</title>
</head>
<body>
    <h1>歡迎登錄:{{ current_user }}</h1>
</body>
</html>

登錄到進入首頁後,看一下瀏覽器中的cookie有哪些值:
在這裏插入圖片描述
把👆demo跑起來,實際調試下瀏覽器,初步理解cookie是做什麼。

Cookie 相關api

設置cookie 都是response.py裏面的方法,比如上面用的就是第一種:res.set_cookie(‘username’, u)

  • 第一種:def set_cookie()
  • 第二種:def set_signed_cookie
HttpResponse(...) 或 rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密鹽',...)
    參數:
        key,              鍵
        value='',         值
        max_age=None,     超時時間
        expires=None,     超時時間(IE requires expires, so set it if hasn't been already.)
        path='/',         Cookie生效的路徑,/ 表示根路徑,特殊的:跟路徑的cookie可以被任何url的頁面訪問
        domain=None,      Cookie生效的域名
        secure=False,     https傳輸
        httponly=False    只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)

取cookie
也有兩種方法,其實針對不同的設置對應不同的獲取方法,對於第二種加鹽處理的算法,django已經爲我們做了。

request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    參數:
        default: 默認值
           salt: 加密鹽
        max_age: 後臺控制過期時間

上面的demo我們就是這樣獲取的:

v = reqeust.COOKIES.get('username')

分析流程

有沒有發現👆的獲取cookie和設置cookie是怎樣的操作流程:

  • response裏面設置cookie,返回到客戶端【瀏覽器】
  • 通過request來獲取cookie
  • cookie其實是存在客戶端【瀏覽器裏面的】
    所以我們是不是可以得到以下結論:
  • 在請求和響應的過程中,cookie其實就是在請求頭裏面的,所以Server端能夠設置和獲取
  • 既然在客戶端,那麼這個cookie其實也是可以在客戶端進行重寫的

優缺點

優點:

  1. http請求的無記憶性;
  2. 加快訪問速度
  3. 減少服務器壓力

缺點

  • 大小限制了,太小
  • 安全因素太低,一般通過加密和session共同使用
  • 客戶端可能禁用cookie,導致cookie不可用

特點

  • cookies保存在客戶端瀏覽器上的鍵值對,且每次訪問頁面都會帶着cookies
  • cookies可以主動清除
  • cookies也可以被"僞造",可以被別人帶着cookies操作你的賬號
  • cookies會根據域名進行分類,不能跨域共享,也就是說百度有百度的,JD有京東的
  • cookies必須請求數據成功後纔能有用哈
  • 瀏覽器可以設置不接收Cookies
  • 服務器端設置的cookies
  • cookies可以設置超時時間, max_age=10

完整Demo地址下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章