iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Security

Izumi從零開始的30日WEB馬拉松系列 第 15

Day15-認識Session與Session基本攻防

  • 分享至 

  • xImage
  •  

今天我們要來學Session,這個東西與JWT有點類似,所以我們今天先學Session,這樣明天我們就能針對兩者進行比較。

什麼是Session?

Session是儲存在伺服器端的使用者狀態資訊,伺服器通常會透過Cookie(通常是sessionid)來識別用戶,並在伺服器端的資料庫或記憶體中保存資料,而Session的特點是將資料儲存在伺服器端,但同時會占用伺服器資源。

Session的攻擊類型

Session Fixation(會話固定攻擊)

攻擊者先給受害者一個已知的Session ID,讓受害者登入後,攻擊者就能用同一個Session進入帳號。

範例:http://victim.com/login?sessionid=12345

Session Hijacking (會話劫持)

攻擊者竊取使用者的 Session(通常透過Cookie偷到sessionid)

Session Timeout 不當設定

如果Session永遠不過期,攻擊者可以長期利用竊取到的Session

遇到Session攻擊的防禦方法

  • 登入後重新產生Session ID,防禦 Session Fixation
  • 設置Session過期時間,避免長期劫持
  • 綁定Session與使用者環境,例如 IP、User-Agent驗證
  • 盡量將URL傳遞放在Cookie避免放在Session ID

今日實作

今天我們將會針對Session的攻擊展開演練,其中包含了攻擊方法以及如何針對弱點進行修正

準備測試環境

首先請先將以下的session_attack.py儲存

#session_attack.py
from flask import Flask, request, make_response, redirect, url_for, render_template_string
import uuid

app = Flask(__name__)

# Server-side session store (very naive)
SESSIONS = {}  # sid -> {username, last_active}

LOGIN_PAGE = """
<h2>Login (For Sesion Attack)</h2>
<form method="POST" action="/login">
  Username: <input name="username"/>
  <input type="submit" value="Login"/>
</form>
"""

HOME_PAGE = """
<h2>Home</h2>
<p>Hi {{username}}! (sid={{sid}})</p>
<form method="POST" action="/logout"><input type="submit" value="Logout"/></form>
"""

@app.route("/")
def index():
    # If attacker supplies ?sessionid=XYZ, we accept it (vulnerability)
    sid_from_query = request.args.get("sessionid")
    sid = request.cookies.get("sid") or sid_from_query
    if sid and sid in SESSIONS:
        user = SESSIONS[sid]["username"]
        resp = make_response(render_template_string(HOME_PAGE, username=user, sid=sid))
        # note: cookie has no HttpOnly / Secure / SameSite set
        return resp
        resp.set_cookie("sid", sid)
    return render_template_string(LOGIN_PAGE)

@app.route("/login", methods=["POST"])
def login():
    username = request.form.get("username", "guest")
    # Vulnerable behavior: if client already sent a sid (cookie or query), we DO NOT rotate it.
    sid = request.cookies.get("sid") or request.args.get("sessionid") or str(uuid.uuid4())
    SESSIONS[sid] = {"username": username}
    resp = make_response(redirect(url_for("index")))
    # insecure cookie: no HttpOnly, no Secure, no SameSite
    resp.set_cookie("sid", sid)
    return resp

@app.route("/logout", methods=["POST"])
def logout():
    sid = request.cookies.get("sid")
    if sid and sid in SESSIONS:
        del SESSIONS[sid]
    resp = make_response(redirect(url_for("index")))
    resp.set_cookie("sid", "", expires=0)
    return resp

if __name__ == "__main__":
    app.run(host='127.0.0.1',port=5000,debug=False)
操作步驟

1.先執行session_attack.py
2.開啟分頁A,http://127.0.0.1:5000/?sessionid=attacker-sid-001 ,這個步驟可以建立一個已知的Session ID
3.接下來我們在分頁A進行登入,輸入attacker後按登入,這樣程式就會把attacker-sid-001與attacker進行關聯,之後按登出
4.現在我們開啟分頁B模擬受害者,輸入victim後進行登入,因為server接受query sid,登入後victim的帳號會和attacker-sid-001進行綁定
5.攻擊者這時重新打開http://127.0.0.1:5000/?sessionid=attacker-sid-001,就會看到 victim 的帳號被讀出

弱點

在這個測試中有幾個漏洞存在導致會被利用

1.程式接受?sessionid=作為sid,如果攻擊者先發一個已知 sessionid(例如 12345)給受害者,受害者登入後 server 用那個 sid 關聯帳號(session fixation)

2.Cookie沒有HttpOnly/Secure/SameSite,session管理非常簡單且可被猜測或重複使用。

3.登入時沒有產生新的隨機sid(session rotation),舊sid繼續有效

修正

這項程式我們可以針對幾項地方進行修正,使網站變安全

1.不接受客戶端提供的sid作為登入後的Session ID
2.登入時強制產生新的Session ID
3.伺服器端記錄最後活動時間實現到期後刪除
4.登出時清除伺服器 session

今日小結

今天我們學習了Session的基礎知識,以及基本的Session實作,了解Session的運作模式,以及如何防範Session被惡意利用遭到攻擊,明天我將針對Session與JWT進行比較與分析。


上一篇
Day-14 認識JWT與JSON
下一篇
Day16-Session與JWT的比較
系列文
Izumi從零開始的30日WEB馬拉松22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言