National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 16

權限與資料的擁有者

401 與 403、角色、不能只靠隱藏按鈕
Interaction實作 30 minute(s)

Learning Objectives

  • 分辨 401 與 403,知道各自什麼時候用
  • 找出並修好「改網址就看到別人資料」的漏洞(IDOR)
  • 用裝飾器寫出角色檢查 require_role
  • 說明為什麼隱藏按鈕不算權限,以及為什麼不能相信表單傳來的 user_id

登入之後還有一個問題

上一課確認了「你是誰」(驗證,authentication)。這一課處理「你可以做什麼」(授權,authorization)。

兩件事常被混在一起,但檢查的東西不同:

問題 沒通過時的狀態碼
驗證 你是誰? 401:伺服器不知道你是誰,請先登入
授權 你可以做這件事嗎? 403:知道你是誰,但你沒有這個權限

很多網站只做了前面一半:只要登入,什麼都看得到。OWASP Top 10:2025 把存取控制失效(Broken Access Control)列為第一項,這類問題非常普遍,而且不需要特殊工具,改一下網址就能試。

逐步看:401、403 與 200

同一個網址,由沒登入的人、學生、老師各開一次。注意 wrapped 在哪一行就結束了,grades 這個 view 函數只有一次被呼叫。

401 與 403 在實務上怎麼用

  • API:照上面的定義回 401 或 403,由前端決定怎麼處理。依 HTTP 規格,401 要附上 WWW-Authenticate 標頭說明認證方式;Flask 的 abort(401) 不會自動加,正式的 API 要自己補。
  • 給人看的網頁:沒登入時通常直接轉到登入頁(302),就是上一課 login_required 的做法。已登入但權限不足時回 403,並放一個自訂的錯誤頁(第 7 課)。

角色怎麼存?最簡單的做法是 users 資料表多一個 role 欄位,每次請求從資料庫查。如果把角色放在 session,老師把某人的權限拿掉之後,對方的 Cookie 裡還是舊的角色。

下面看一個更隱蔽的問題:大家都是學生,角色一樣,資料卻各是各的。

逐步看:改網址就看到別人的筆記

Amy(編號 1)依序開三種版本的網址。比較每個版本的 SQL,以及 Ben 的筆記在哪個版本被擋下來。

互動練習:修好看得到別人筆記的漏洞

這是一個真的會出問題的小網站。先用網址列實際看到漏洞,再改程式修掉。

要修的是 app.py 最下面的 note:讓查詢同時比對筆記編號與 session['user_id']。修完按「存檔並重新啟動」,再回網址列試。

這些操作只在你瀏覽器裡的模擬網站上進行。 在別人的網站上「試試看改網址」,即使只是好奇,也可能違法;發現真實網站有問題時,請依對方公布的管道回報。

回 403 還是 404

剛才的修法查不到就回 404。另一種寫法是先查出來、比對後回 403。兩種都擋得住,差別在於要不要讓對方知道這筆資料存在:

回 403 回 404
對方知道什麼 這個編號有資料,只是不屬於你 分不出是不存在還是不屬於你
適合 資料的存在本身不敏感,例如課程頁面,或需要提示「請向老師申請權限」 私人資料,例如筆記、訊息、成績。OWASP 建議這類情況對「不存在」與「無權限」回相同的回應

另外,把編號換成不容易猜的 UUID 可以提高猜中的難度,但不能取代檢查:網址一旦被分享或外流,對方還是打得開。OWASP 也提醒,把編號藏起來不算足夠的防護,每個請求都要檢查。

逐步看:表單傳來的 user_id 不能信

表單裡常有 <input type="hidden" name="user_id">。隱藏欄位只是畫面上看不到,送出前一樣改得了。下面的程式就是直接送一個別人的編號。

只藏按鈕不算權限

依權限顯示按鈕是對的:使用者不該看到按了也沒用的按鈕。但這只是介面,不是防線。

{% if user['role'] == 'teacher' %}
  <button>刪除</button>     <!-- 只有老師看得到按鈕 -->
{% endif %}

模板只決定回傳的 HTML 長什麼樣子。POST /announcements/1/delete 這條路由還在,任何人都可以直接送請求,開發者工具、curl 或幾行 Python 都做得到。

原則:所有權限判斷都要在伺服器端做,而且依據伺服器自己的資料。

不可以當依據 可以當依據
表單、網址、JSON 傳來的 user_id 或 role session 裡的使用者編號
按鈕有沒有顯示 資料庫裡的角色與擁有者
前端 JavaScript 的判斷

下面實際試一次。

互動練習:學生刪得了公告嗎

畫面上方是瀏覽器,下方是 API 工具。兩者共用同一組 Cookie,就像你在同一個瀏覽器裡開了開發者工具。

require_role 已經寫好,但刪除公告的路由沒有用它。要修的地方是在 delete_announcement 上面加一行裝飾器,位置要對:路由在最上面。

每次重新啟動,範例會把公告補回來,方便你重複試。按鈕「刪除公告 1」「刪除公告 2」會把請求填進 API 工具,再按「送出」。

動手做:只看得到自己的筆記

完成 note:沒登入回 401;查詢同時比對編號與登入者,所以別人的筆記和不存在的筆記都回 404。SQL 一樣用 ? 當參數。程式最下面的測試不要改。

你的輸出
預期輸出

想一想

1.

一位已登入的學生打開只有老師能看的成績頁。比較適當的狀態碼是?

2.

下面程式登入的是編號 1,執行後會印出什麼?

from flask import Flask, session, abort

app = Flask(__name__)
app.secret_key = 'dev'
notes = {1: 1, 2: 2}     # 筆記編號對應擁有者

@app.route('/login')
def login():
    session['user_id'] = 1
    return 'ok'

@app.route('/notes/<int:nid>')
def note(nid):
    if notes.get(nid) != session.get('user_id'):
        abort(404)
    return '筆記'

client = app.test_client()
client.get('/login')
print(client.get('/notes/1').status_code, client.get('/notes/2').status_code, client.get('/notes/9').status_code)
3.

編輯筆記的表單裡有 <input type="hidden" name="user_id" value="1">,後端用 request.form['user_id'] 決定要改誰的筆記。問題是?

4.

老師的刪除按鈕用 {% if role == 'teacher' %} 包起來,後端路由沒有其他檢查。學生能不能刪除?

5.

課程的私人訊息頁,要回答「這筆訊息不是你的」。下面哪個說法最恰當?

第 1 次作答

重點整理

  • 401 是不知道你是誰,403 是知道你是誰但沒有權限
  • 登入不等於有權限:每個讀取或修改單筆資料的路由,都要檢查這筆資料是不是你的(IDOR)
  • 最簡單的修法是把擁有者寫進查詢:WHERE id = ? AND user_id = ?
  • 私人資料查不到就回 404,不透露資料是否存在;存在本身不敏感時可以回 403
  • 角色用 require_role 裝飾器集中檢查,角色從資料庫查
  • 按鈕依權限顯示只是介面;檢查要寫在後端,依據 session 與資料庫,不信任表單傳來的 user_id

這一課的攻擊者是登入的使用者。下一課看來自外面的攻擊:SQL 注入、XSS 與 CSRF。

這一課完成了!
Next lesson:常見攻擊與防護
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。