iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 20
0
Software Development

後端基礎PHP+Mysql & Laravel 30日養成計畫系列 第 20

Day 20 Authentication基礎概念介紹:session、cookie and token

除了用post、get等方式在網頁間傳送資料外,session、cookie和token也是在網路應用程式中經常使用來儲存使用者資料的機制。由於http是無狀態的,也就是說,client端每次對server發出的請求都是獨立的,server並不會記住client所發出的每個請求的歷史資訊,因此必須靠這些機制來克服http協議的無狀態性,來使某個域名下的所有網頁都能共享這些資訊。例如記住使用者是否已經登入等資訊,就是透過cookie、session和token等來傳送登入憑據,如此一來使用者就不必在每次要跳到下個頁面的時候都得重新登入一次
那為何不直接記住使用者帳密就好,為什麼還需要設計組『能代表使用者』的識別碼來取代帳密呢?很多人在各個網站使用的帳密可能都是同一組,如果記下使用者帳密作為身份代表,只要帳密被有心人士拿到,他不僅能登入這個應用程式,也可能拿這組帳密去登入其他應用程式,除非請使用者重新設定一次,否則這組身份識別資料是永久有效的;使用session token來作為登入憑據則可設定其期效,過期後可以作廢再生成新的。

傳遞 session

由於 cookie 是存在 client 端,所以在不同程式之間的傳遞都可以藉由使用者本身的檔案來存取所需的資訊,但 session 是儲存在 server 端,除非使用者告訴 Server Session 資訊檔案名稱是什麼,不然是無法傳遞「session 值」(就是 sess_後面加的 32 字元), 因此一般來說,會利用兩種方式來傳遞「 session 值 」:

  1. 透過 URLs(因網路安全考量,現在大多不用此種方法)
  2. 透過 Cookie

client端訪問server端的流程:

  1. client端發送一個http request到server端
  2. server接到request後,建立一個session(可視作為一種狀態列表,每個Session都有屬於它自己的id識別碼),並傳送一個http response回client端,而這個response包括Set-cookie的header,裡面存有sessionID。
    Set-cookie會長這樣:

Set-cookie:value[; expires=date][; domain-domain][; path=path][; secure]

  1. 當client端發出第二次request後,若server給了Set-cookie,瀏覽器會自動在request中加入cookie。
  2. server接受request,解析並驗證cookie,若驗證成功就回傳response給client端;失敗則回除錯誤碼。

儲存位置

session是可能將使用者資訊儲存在server端的資料庫、Memory暫存檔中,端看實作方式。
而cookie則將資訊儲存在client端,通常存在瀏覽器,或local storage,也就是使用者自己的電腦,儲存的位置一般是放在:

  • C:\Documents and Settings\電腦帳號\Cookies (Windows NT/2000/XP)
  • 或 C:\Documents and Settings\帳號\Local Settings\Temporary Internet Files\
  • 或 C:\windows\Cookies (Windows 98)

cookie 的限制

實際的作法大多會使用session+cookie,其實要單獨只用其中一個理論上也是行得通,但因種種原因,通常不會單獨只使用session或只使用cookie。
只用session的話,只會在client端儲存一個id,而實際上大部分的資訊都是存在server端;
(大多session的實作,會將session id存在會話cookie中,當使用者關閉瀏覽器,session id也會不見;但若cookie是存在硬碟中,則再次開啟瀏覽器時,之前存的資料還是會存在)
相反的,如果資訊大多存放在cookies(例JWT),一來資訊量大的時候client端可能沒有足夠的空間來儲存,二來因為所有資訊都存在client端,一旦你的電腦被挾持,所有資訊都有可能曝光。而且隨著client端的資訊量變大,網路傳輸的數據量也會變大。

因為 cookie 常常用來存取使用者的資訊,為了怕被拿來濫用,或是佔用太多硬碟空間,
所以對 cookie 做出了以下的限制:

  • 每個使用者的瀏覽器只能支援(存取)300 個 cookie
  • 每個瀏覽器只能針對同一個伺服器存取 20 個 cookie
  • 每個 cookie 的大小最多僅 4k Bytes 的容量
  • 有些瀏覽器可以把 cookie 的功能關掉,若關掉後 cookie 就不能使用

token

token是當使用者登入成功後,server端產生並回傳的一組能象徵該使用者的『權杖』。
實作方式有很多種,端看server端怎麼寫。
舉個例子:
token由uid+time+sign[+固定參數]構成:
uid: 使用者具唯一性的身份辨識碼
time: 當前的時間戳記
sign: 使用hash/encrypt壓縮成長度固定的16進制string,以防止第三方惡意拼湊。
固定參數(可有可無):將一些常用的固定參數加到token中,以避免重複查詢。

儲存位置

傳統的身份驗證方式,是將token在client端存放於cookie(localStorage, 瀏覽器)中。在server端則存放於資料庫中。

以會員登入流程為例:

  1. 使用者登入後,將token回傳給client端
  2. client端收到資訊後存在client端
  3. 當client端再次訪問server時,將token存放在header中
  4. server透過filter驗證token,驗證成功就回傳request資訊;失敗則回傳錯誤碼。

小結

  1. session或cookie就像是使用者檔案,裡面儲存了使用者的驗證資訊和登入狀態,和其他使用者相關資料(例如使用者在應用程式選擇的頁面樣式、暱稱等)
  2. 可將session視為一種狀態列表,每個Session都有屬於它自己的id識別碼,這個sessionID通常存在cookie中。當server收到cookie後,會解析出seesionID,然後去session列表中找到相對應的session。
  3. 而cookie就只是其中用來驗證的使用者識別碼,裡面存有sessionID,存放在client端,瀏覽器通常會自動將cookie加進來。
  4. token也是一種識別碼,可將使用者資訊加密變成token,當server收到token後加以解密就能辨識出是哪位使用者了。
  5. 無論以什麼方式實作session, cookie和token,都有一個風險:只要任何人拿到這組代表使用者身份的識別資訊,都可以取代該使用者進行非本意的操作,這是省下每次輸入帳密這個麻煩所必須付出的代價。因此限制session, cookie和token的期效在一些對於資安要求較高的情境(例如涉及付款資訊的應用程式)是很重要的。

PHP中的session

在PHP中,可以用$_SESSION 這個array來存取session資料。
session儲存的位置是依照 php.ini 的設定。
每支檔案中若有使用到session都要在最開頭加入session_start();以啟用session
這個變數其實在上回的留言板實做中就有出現過,以下是擷取view.php其中一段程式碼:

<?php
session_start(); //啟用session
include "db.php";
$sql = "select * from guestbook";
$result = mysqli_query($db, $sql);
//將$_GET['name']的資料存放到$_SESSION['name']這個欄位中,以便傳送給下個要跳轉過去的頁面
$_SESSION['name'] = $name = $_GET['name']; 

delete.php

session_start(); 
include "db.php";
$db = mysqli_connect("localhost", "userName", "*******", "board") or die(mysqli_error());
$no = $_SESSION['no'];
$sql = "delete from guestbook where no='$no'";
$name = $_SESSION['name']; //把session記錄的使用者名稱存到$name這個變數
mysqli_query($db, $sql);
if (!mysqli_query($db, $sql)) {
	die(mysqli_error());
} else {
 //跳轉頁面時帶著使用者名稱到下個頁面
	echo "
         <script>
            setTimeout(function(){window.location.href='view.php?name=" . $name . "&no=" . $no . "';},300); 
        </script>";
}

補充:簡單介紹編碼、雜湊和加密的區別

  1. 編碼:可逆(可被decode),常見編碼方式有base 64。
  2. 雜湊:不可逆,由雜湊值無法回推出原始值,常見雜湊法有sha1, sha256, md5(sha1, md5因有安全疑慮不建議使用)。常見用途在於檢查資料是否有效,有無損壞或被竄改。最簡單的雜湊就是取餘數,例如身分證字號最後一碼,就是將前面9碼一權重相加之後取10的餘數而得。
  3. 加密:可逆,但需要一把key才能解碼,分為對稱和非對稱。對稱即用一把key加密後的資料可由同一把key解密;非對稱則是加密和解密為不同把key。常見加密方法有rsa(非對稱,由一組公鑰和私鑰組成)

上一篇
Day 19 留言板實做(三):編輯、刪除留言
下一篇
Day 21 實做猜數字遊戲(一):遊戲介紹
系列文
後端基礎PHP+Mysql & Laravel 30日養成計畫36

尚未有邦友留言

立即登入留言