先由表單控制項形成 name=value,再追蹤 GET/POST 請求、PHP 接收、有效性檢驗、安全輸出及狀態保存。
1HTML 表單:從零建立與常用輸入元件
學習重點
<form>用於收集輸入:action指定提交目標,method指定 GET 或 POST。name代表「提交欄位名稱」:PHP 以$_GET["name"]或$_POST["name"]取值。id主要供 CSS/JavaScript 選取、以及<label for>對應;不等同提交欄位。- 常用輸入元件:
text、password、date、time(時間選擇器)、select、複選框(checkbox)、submit。
瀏覽器提交表單時,並不會把整個 HTML 送到伺服器,而是把具備 name 的欄位整理成一組 name=value 的資料,再送至伺服器端程式處理。
action:提交到哪個 URL(通常是某個 PHP 檔案)。method:資料如何傳送;常用get或post。
name:伺服器端取值用(提交鍵)。id:前端定位用(CSS/JS/label)。
常見錯誤是只寫 id 而忘記 name,導致 $_POST/$_GET 取不到資料。
若同一組複選框要提交多個值,可用 name="hobby[]" 令 PHP 以陣列形式接收,再用 foreach 逐項處理。
表單骨架:最少需要哪些欄位?
- 提交目標:
action指向負責處理的 PHP 檔案。 - 提交方法:
method決定用$_GET還是$_POST接收。 - 欄位命名:每個需要提交的元件必須具備
name。
常用輸入元件與適用情境
| 元件 | HTML 範例 | 常見用途 | 注意事項 |
|---|---|---|---|
| 文字框 | <input type="text" ...> |
姓名、關鍵字、一般文字 | 仍需伺服器端有效性檢驗(例如長度) |
| 密碼框 | <input type="password" ...> |
密碼輸入 | 只遮蔽顯示,不代表安全;不可把明文密碼存入曲奇 |
| 日期 | <input type="date" ...> |
生日、日期選擇 | 不同瀏覽器呈現略異;伺服器端仍要檢查格式 |
| 時間 | <input type="time" ...> |
預約時間、上課開始時間 | 伺服器端仍要檢查格式與合理範圍(例如只接受 08:00–18:00) |
| 下拉式選單 | <select name="...">...</select> |
班別、選項限制輸入範圍 | 伺服器端應用 in_array() 驗證值是否在允許清單 |
| 複選框 | <input type="checkbox" ...> |
興趣多選 | 多值建議用 name="x[]",伺服器端以陣列接收 |
| 提交按鈕 | <button type="submit">...</button> |
提交表單 | 可配合必填提示,但不可取代伺服器端檢查 |
代碼小練習:表單實作(2 個任務)
每個任務均提供:提示/核對答案/顯示參考答案。請在下方以分頁切換任務,逐題完成。
任務 1:重組示範表單(填寫 action/method/class)
- 只修改標示為
TODO的位置:action、method、以及每個label的class。 - 完成後按「核對答案」:系統會檢查表單是否使用指定的提交位置及排版類別。
任務 2:情境題:設計一個「活動預約表單」
- 依題目要求,在表單內同時使用:
text、password、date、time、select、checkbox、submit。 - 只需要完成 HTML(本題不要求 PHP 處理)。
2GET 與 POST 的選用原則
重點
- GET 把參數放在劃一資源定位(URL)的查詢字串;POST 把參數放在請求主體(request body)。
- GET 參數通常可見,搜尋或篩選結果較容易加入書籤及分享;POST 提交內容一般不會成為網址的一部分。
- GET 受網址長度限制;POST 通常可傳送較多數據,並較適合建立、更新或提交表單。
- POST 本身不等於加密;敏感數據仍須透過 HTTPS 傳輸,並在伺服器端作有效性檢驗及權限檢查。
GET 與 POST 都是瀏覽器向伺服器提交請求時可使用的方法。GET 的參數通常附加在 URL 的查詢字串;POST 的參數通常放在請求主體,PHP 分別以 $_GET 與 $_POST 讀取。
使用 GET 時,瀏覽器可把例如 ?q=php&page=2 的參數連同網址傳送,因此網址可重現同一個搜尋狀態。使用 POST 時,表單數據放在請求主體;重新整理頁面時,瀏覽器可能提示重新提交,以免重複執行更新操作。
無論採用哪一種方法,伺服器都必須檢查參數;把數據顯示回 HTML 前亦應按輸出情境編碼。
搜尋頁可使用 /search.php?q=php&page=2,讓用戶收藏或分享相同結果。登入表單則通常使用 POST,避免密碼出現在網址、瀏覽器歷史或一般連結中;但登入頁仍必須使用 HTTPS,因為 POST 並不會自行加密內容。
- 位置與可見性:GET 參數在 URL;POST 參數在請求主體,但仍可能被伺服器、代理工具或有權存取裝置的人員看見。
- 書籤與分享:GET 較適合可重現的查詢;POST 一般不適合靠網址重現提交內容。
- 數據量與用途:GET 受 URL 長度限制;POST 通常可提交較多數據,並適合會改變伺服器狀態的操作。
- 誤以為 POST 等於加密,因而忽略 HTTPS。
- 把密碼或身份數據放入 GET,令內容留在網址、歷史或日誌。
- 把需要分享的搜尋條件改用 POST,令用戶不能以網址重現結果。
- 假設 POST 可傳送無限數據;實際上仍受瀏覽器、伺服器及應用設定限制。
由目的決定請求方法
選擇 GET 或 POST 時,應先判斷請求的目的,而不是只看表單外觀。搜尋、排序、篩選與分頁通常只是讀取資料,而且用戶可能需要收藏或分享結果,所以 GET 較自然。登入、註冊、上載內容,以及新增、更新或刪除紀錄,通常會提交較多數據或改變伺服器狀態,因此一般採用 POST。
兩者最明顯的分別是參數位置。GET 參數成為 URL 的一部分,容易在地址列、瀏覽器歷史、伺服器日誌及分享連結中出現;POST 參數不直接顯示於 URL,但這只改變傳送位置,並沒有提供加密。敏感數據必須經 HTTPS 傳輸,伺服器亦要核對登入狀態、權限及輸入是否符合要求。
PHP 以 $_GET 或 $_POST 取得提交內容後,仍應把所有值視為外來輸入。程式應先作伺服器端有效性檢驗,再按用途處理;當內容要輸出至 HTML 時,使用適當輸出編碼,例如 htmlspecialchars(),可避免數據被瀏覽器誤解為標記。
差異、優缺點與適用情境(表格)
| 比較項 | GET | POST |
|---|---|---|
| 參數位置 | URL 查詢字串(可見) | request body(URL 不直接顯示) |
| 可分享/可書籤 | 容易(URL 包含參數) | 一般不便(URL 不含提交內容) |
| 私隱與保安 | 較弱:容易被記錄於瀏覽器歷史、伺服器日誌 | 不直接顯示於 URL,但 POST 本身不等於加密;敏感數據仍須使用 HTTPS |
| 數據量 | 受 URL 長度限制 | 一般可提交較多資料 |
| 常見用途 | 搜尋、排序、篩選、分頁 | 登入、註冊、提交表單、更新/刪除操作 |
選用原則:以問題導向作判斷
- 需要分享或收藏結果嗎?若需要,通常選 GET(例如搜尋結果)。
- 包含敏感資料嗎?若包含(例如密碼、身份數據),一般以 POST 提交,並必須配合 HTTPS;POST 本身不會加密。
- 資料是否會改變伺服器狀態?若會(新增/更新/刪除),一般選 POST(或其他方法)。
- 數據量是否較大?若較大,通常選 POST。
即時示範:GET 搜尋(顯示輸入)
Checkpoint:GET 與 POST 的選用原則(≥40 題)
本小測以四選一為主,涵蓋情境判斷、URL 可見性、長度限制與私隱風險。
3伺服器端有效性檢驗:不可只依賴客戶端
重點
- 客戶端檢查可改善界面體驗,但可以被停用、修改或繞過;伺服器端必須重新檢查。
- 有效性檢驗可包括:存在、數據類型、範圍、格式、長度,以及是否屬於白名單。
- 檢查次序通常由基本條件開始,再檢查較具體規則,並只在全部通過後處理數據。
- 有效性檢驗判斷數據是否合理;校驗則確認輸入是否與原始資料一致,兩者不可混淆。
伺服器端有效性檢驗是指伺服器收到輸入後,依照預先訂定的規則判斷數據是否可接受。檢驗可涵蓋欄位是否存在、是否為必填、數據類型、數值範圍、格式、長度及白名單。
穩妥流程可依次檢查:欄位存在 → 必填內容不為空 → 數據類型或格式正確 → 長度與範圍合理 → 值屬於允許清單。任何一步失敗便停止相關處理,並回傳不洩露系統細節的提示。
客戶端檢查只能提供即時提示;伺服器不可假設請求必定來自原本的表單界面。
班別報名表可要求姓名存在且長度不超過指定字數、年齡可轉為整數並介乎合理範圍、電郵符合指定格式,而班別值必須是 1A、1B 或 1C 其中之一。全部規則通過後才保存紀錄。
- 客戶端檢查:反應快、改善體驗,但可被繞過。
- 伺服器端檢查:是資料進入應用邏輯前的必要把關。
- 有效性檢驗:判斷「是否合理」;例如年齡是否在 0 至 120。
- 校驗:判斷「是否與原始資料一致」;例如要求再次輸入電郵並比較兩次內容。
- 只依賴 HTML 的
required、輸入類型或 JavaScript。 - 只檢查欄位存在,卻沒有檢查內容、格式、長度及範圍。
- 對固定選項不設白名單,誤以為下拉式選單不能被繞過。
- 把通過有效性檢驗誤解為資料必定真實、屬於該用戶或已獲授權。
所有外來輸入均需重新檢查
瀏覽器端的必填提示、數字輸入框及下拉式選單,能讓用戶較早發現問題,但這些限制只存在於客戶端。請求可由其他程式送出,界面設定亦可被改動,因此伺服器收到數據後必須根據同一套業務規則重新作有效性檢驗,不能因為表單看似受限制便直接信任。
檢驗規則應與欄位用途相配合。文字可檢查存在、數據類型、最短及最長長度;數值可檢查能否正確轉換及是否在合理範圍;固定選項應以白名單限制;有既定結構的內容則可檢查格式。程式應先完成基本檢查,再執行數據庫操作、計算或輸出,避免無效數據進入後續流程。
有效性檢驗只表示數據符合規則,不代表內容真實、身份已確認或操作已獲授權。校驗則著重輸入與原始資料是否一致。實際系統仍要另外處理身份核對、權限控制、輸出編碼及參數化查詢等防護。
常用函數速查:檢查甚麼、回傳甚麼、常見陷阱
| 函數 | 檢查內容 | 回傳值(重點) | 常見陷阱/注意 | 簡例 |
|---|---|---|---|---|
isset($x) |
變量是否存在且不為 null |
布爾值:存在且非 null → true |
只代表「存在」,不代表「不空」 | if(isset($_POST['name'])) ... |
empty($x) |
是否為「空值」 | 布爾值:空 → true |
"0" 亦視為空;若 0 合法,應改用更精準判斷 |
if(empty($_POST['age'])) ... |
in_array($v,$arr) |
值是否在允許清單(白名單)內 | 布爾值:找到 → true |
必要時使用第三參數 true 作嚴格比較 |
in_array($cls,$allow,true) |
is_numeric($x) |
是否可視為數值 | 布爾值 | 通過後仍建議轉型(例如 (int))再作範圍檢查 |
if(!is_numeric($age)) ... |
is_string($x) |
是否為字串(string) | 布爾值 | 表單輸入多數是字串;更常用的是長度/格式/白名單 | if(is_string($name)) ... |
strlen($s) |
字串長度 | 整數 | 用於最少/最多字元限制;輸入前可先 trim() |
if(strlen($pw)<8) ... |
strpos($s,$sub) |
子字串首次出現的位置 | 整數位置或 false |
0 代表「在第一個位置找到」;判斷找不到必須用 === false |
if(strpos($email,'@')===false) ... |
代碼小練習:以多個函數完成輸入檢查(填空題|7 個任務)
請以分頁切換任務。每個任務均提供:提示/核對答案/顯示參考答案/講解;請只修改題目標示為 TODO 的位置。
任務 1:用 isset() 檢查欄位是否存在
- 在伺服器端先確認必須欄位(例如
user、age)是否存在於$_POST。 - 如缺少欄位,請把訊息加入
$errors,並輸出錯誤清單。
任務 2:用 empty() 檢查必填欄位
- 把輸入
trim()後,再用empty()檢查是否留空。 - 如留空,請輸出清楚的錯誤原因(例如「用戶名稱不可留空」)。
任務 3:用 is_numeric() 檢查數值(並加上範圍)
- 檢查年齡是否為數字;若不是,加入錯誤。
- 如是數字,請把它轉為整數並檢查範圍(例如 1–120)。
任務 4:用 is_string() 與 strlen() 檢查字串長度
- 檢查用戶名稱是否為字串(示範用途),並限制長度介乎 3–12 字元。
- 如不符合,請輸出對應錯誤訊息。
任務 5:用 in_array() 做白名單驗證(選單值)
- 把允許值寫成陣列(白名單),再用
in_array()驗證。 - 建議使用嚴格比對(第三個參數設為
true)。
任務 6:用 strpos() 檢查格式(處理 0 的陷阱)
- 檢查電郵是否包含
@。 - 提示:
strpos()找到位置 0 代表「在第一個字元找到」;判斷找不到必須用=== false。
任務 7:綜合練習:串連多個函數完成輸入檢查
- 按「存在 → 必填 → 格式 → 範圍/白名單」的順序完成檢查。
- 把所有錯誤集中顯示(不要只顯示第一個錯誤)。
Checkpoint:伺服器端有效性檢驗(≥40 題)
本小測以四選一為主,包含:函數配對、常見陷阱(特別是 strpos())、以及程式片段判讀。
4曲奇(Cookie):用途、好處與壞處、適用與不適用情境
重點
- 曲奇是由網站要求瀏覽器保存的小型數據,主要儲存在瀏覽器端,日後符合條件的請求可把它帶回伺服器。
- 曲奇包含名稱、值及有效期等資料;路徑、網域與安全屬性會影響何時傳送及能否被腳本讀取。
- 常見用途包括記錄語言、主題等偏好,以及保存不透明的登入狀態識別碼。
- 曲奇容量有限,並涉及追蹤與私隱;不可把密碼、身份號碼或其他敏感數據以明文存入曲奇。
曲奇(Cookie)是網站要求瀏覽器保存的一小段名稱與值資料。瀏覽器在其有效期、網域及路徑等條件符合時,通常會在後續請求把曲奇傳回相應網站。
伺服器可透過回應設定曲奇,指定名稱、值、有效期、路徑及網域。Secure 可限制曲奇只經 HTTPS 傳送,HttpOnly 可限制客戶端腳本讀取,而 SameSite 可協助控制跨網站請求中的傳送情況。
曲奇內容仍由瀏覽器持有,伺服器必須把它視為可能被刪除或改動的外來輸入。
網站可用曲奇記住「繁體中文」「深色界面」或「已關閉導覽提示」等偏好。登入系統亦常以曲奇保存一個隨機、不透明的 Session identifier,再由伺服器找回真正的登入狀態,而不是把密碼或完整權限資料放進曲奇。
- 持久曲奇:設有有效期,可在關閉瀏覽器後繼續保存至到期或被刪除。
- 工作階段曲奇:通常沒有持久有效期,主要在目前瀏覽工作階段使用。
- Session:主要狀態保存在伺服器端;瀏覽器通常只保存識別碼。
- 把敏感數據、明文密碼或直接決定權限的資料放入曲奇。
- 假設曲奇不能被用戶刪除、改動或複製。
- 刪除曲奇時沒有使用與建立時相同的路徑或網域。
- 忽略容量、有效期、同意要求及追蹤私隱等限制。
曲奇如何協助網站記住狀態
HTTP 請求本身不會自動記住上一頁發生的事情。曲奇讓瀏覽器保存少量名稱與值,並在符合網域、路徑及有效期等條件時帶回網站,因此適合保存語言、界面主題、字體大小及是否看過提示等偏好。曲奇不是大型儲存空間,內容應保持精簡。
曲奇位於瀏覽器端,用戶可以刪除,內容亦可能被改動,所以伺服器不可把曲奇值直接當作可信權限。登入系統較常把一個難以猜測的 Session identifier 放在曲奇,再由伺服器端查找實際狀態。敏感數據不可用明文保存;傳輸亦應使用 HTTPS,並按需要設定 Secure、HttpOnly 及 SameSite 等屬性。
設計曲奇時還要考慮有效期、路徑、網域、容量及私隱。有效期過長會增加資料被長期保留的風險;追蹤用途可能需要取得適當同意;刪除時若路徑或網域與建立時不一致,原有曲奇可能仍然存在。
曲奇可存甚麼?不應存甚麼?
- 適合:偏好設定(例如字體大小、界面主題)、非敏感標記(例如「已完成新手導覽」)。
- 不適合:明文密碼、身份證號碼等敏感資料;以及會直接影響權限的關鍵資料(除非配合簽署/伺服器端驗證)。
基本用法:設置與讀取
即使資料來自曲奇,仍應視為外來輸入:必要時要做伺服器端驗證,輸出前亦要使用 htmlspecialchars()。
清除指定曲奇:把有效期設為過去
要成功刪除曲奇,path/domain 等參數必須與原本設置時一致;否則可能出現「看似刪除,但實際上仍存在」的情況。
互動示範:以曲奇(Cookie)記住使用者名稱(可試玩)
情境:網站希望在使用者下次回訪時顯示「歡迎回來,使用者名稱」。
請在下方模擬器輸入名稱並提交,然後再次提交或按「執行」,觀察 $_COOKIE 的變化;再按「清除曲奇」。
注意:此模擬器為教學用途,setcookie() 在同一次執行中亦會即時反映於 $_COOKIE(與真實伺服器環境「下次請求才會讀到」的行為略有差異)。
Checkpoint:曲奇(Cookie)(≥40 題)
本小測以四選一為主,涵蓋用途、好處/壞處、以及情境判斷(應否使用曲奇)。
5Session:概念、基本用法與曲奇的分別
重點
- Session 的主要狀態保存在伺服器端;瀏覽器通常只保存並傳回一個 Session identifier。
- 基本流程是
session_start()、讀寫$_SESSION、檢查登入狀態,並在登出時清除資料並使識別碼失效。 - Session 有生命週期;應設定合理逾時,並在敏感操作後更新識別碼及重新核對權限。
- Session 並非天生安全:識別碼若被竊取、固定或錯誤共用,仍可能導致冒用,因此需要 HTTPS 及其他防護。
Session 是伺服器為某個瀏覽工作階段保存狀態的機制。登入標記、用戶識別碼及暫時購物車等資料主要留在伺服器;瀏覽器一般只保存 Session identifier,用來讓伺服器找回相應紀錄。
PHP 頁面先呼叫 session_start(),讓伺服器讀取或建立 Session。登入成功後,只保存必要狀態;受保護頁面每次均檢查身份與權限。登出時清除 Session 資料、使伺服器端狀態失效,並按需要刪除識別曲奇。
系統亦應設定閒置及最長逾時,並在登入或權限提升後更新 Session identifier。
用戶通過密碼核對後,伺服器可在 $_SESSION["user_id"] 保存其內部識別碼。下一次開啟會員頁時,瀏覽器只送回 Session identifier;伺服器根據它找回 user_id,再查明該用戶目前是否仍有權查看內容。
- 曲奇:資料在瀏覽器端,容量有限,可用來保存偏好或 Session identifier。
- Session:主要狀態在伺服器端,較適合登入及短期狀態,但仍依賴識別碼及伺服器設定。
- 生命週期:關閉瀏覽器、閒置逾時、伺服器清理及主動登出都可能令 Session 結束;不能假設它永久存在。
- 聲稱 Session 天生安全,忽略識別碼被截取或冒用的風險。
- 只隱藏頁面連結,卻沒有在每個受保護請求重新檢查權限。
- 登出時只清除畫面狀態,沒有使伺服器端 Session 失效。
- 沒有設定逾時,或在登入後沿用舊的 Session identifier。
以識別碼連接瀏覽器與伺服器狀態
Session 用來解決 HTTP 請求之間缺乏持續狀態的問題。伺服器為工作階段建立一筆狀態資料,瀏覽器則通常以曲奇保存 Session identifier。之後每次請求帶回識別碼,伺服器便可找回登入用戶、購物車或流程進度等資料,而毋須把完整狀態交給瀏覽器保存。
Session 的使用並不止於呼叫 session_start()。登入成功後應只保存必要資料,受保護頁面必須在每次請求重新檢查身份與權限;登出時要清除伺服器端狀態並處理識別曲奇。系統亦應設定合理的閒置逾時與最長生命週期,避免長期未使用的工作階段繼續有效。
伺服器端保存狀態不代表 Session 自動安全。若識別碼經不安全連線洩露、被固定、被複製或未被妥善設為失效,其他人仍可能冒用工作階段。因此登入流程應使用 HTTPS,設定合適的曲奇屬性,在登入或權限改變後更新識別碼,並把真正權限判斷保留在伺服器端。
甚麼是 Session?為何常用於登入?
HTTP 請求本質上無狀態;若要「記住」某位用戶已通過身份核對,便需要保存狀態。 Session 把狀態資料放在伺服器端,通常只把一個識別碼交由瀏覽器保存並帶回,因此比把完整狀態直接放在曲奇更合適用於登入。
基本流程(示意)
- 在需要使用 Session 的頁面最上方呼叫
session_start()。 - 登入成功後:設定
$_SESSION["logged_in"] = true,並保存必要的用戶識別資料(例如user_id)。 - 受保護頁面:先檢查
$_SESSION是否存在登入標記;不符合則導向登入頁。 - 登出:清除 Session(例如
session_unset()或session_destroy())。
代碼示範:登入、受保護頁面與登出
以下以三個檔案示範最基本流程:登入成功後建立 Session;受保護頁面先檢查 Session;登出時清除 Session。實務上仍需配合 HTTPS、伺服器端有效性檢驗及更嚴謹的權限控制。
login.php(建立 Session)
welcome.php(檢查 Session)
logout.php(清除 Session)
互動示範:以 Session 保存登入狀態(可試玩)
情境:網站需要在多次 HTTP 請求之間保存「已登入」狀態。
請在下方模擬器使用測試帳號登入,觀察登入後內容如何由 $_SESSION 控制;再按「登出」清除 Session。
此示範把「登入頁面」與「會員區」寫在同一檔案內,以便在模擬器中試玩;在真實網站中可拆成多頁並配合導向(redirect)流程。
Session 與曲奇:如何比較?
| 項目 | 曲奇(Cookie) | Session |
|---|---|---|
| 主要儲存位置 | 客戶端(瀏覽器) | 伺服器端 |
| 資料可否被用戶改動 | 較容易(可被修改) | 較難(用戶通常只持有 Session ID) |
| 常見用途 | 偏好、非敏感狀態 | 登入狀態、權限控制 |
| 保安重點 | 不應存敏感資料;內容需驗證 | 保護 Session ID、避免被盜用;伺服器端設計需嚴謹 |
Checkpoint:Session 概念與流程(≥40 題)
本小測以四選一為主,涵蓋 Session 基本概念、session_start()、$_SESSION 用法,以及 Session vs 曲奇分辨。
6防禦性安全:輸入、輸出、數據庫與錯誤訊息
重點
- 所有外來輸入都要在伺服器端作有效性檢驗,不能只信任表單界面或客戶端腳本。
- 把數據輸出至 HTML 前應作情境相符的輸出編碼,例如使用
htmlspecialchars()降低 XSS 風險。 - 存取數據庫時應使用參數化查詢,把 SQL 指令與外來數值分開處理。
- 只收集、保存及顯示完成任務所需的最少數據,並避免向用戶顯示詳細系統錯誤。
防禦性安全是在輸入、處理、數據庫存取、輸出及錯誤處理等每一層採取合適控制。任何單一措施都不足以處理所有風險,因此需要分層防護。
安全流程可概括為:只接收必要欄位 → 在伺服器端作有效性檢驗 → 核對身份及權限 → 以參數化查詢存取數據庫 → 儲存最少數據 → 按輸出情境編碼 → 對用戶顯示一般錯誤,並把詳細資料記錄於受保護日誌。
留言表單可限制留言是否存在及長度,保存前以參數化查詢把文字值交給數據庫驅動程式;顯示留言時再以 htmlspecialchars() 編碼。若操作失敗,頁面只顯示「暫時未能提交」,詳細例外則留在伺服器日誌供管理員調查。
- 有效性檢驗:控制可接受的輸入。
- 輸出編碼:防止數據在特定輸出情境被當成可執行標記。
- 參數化查詢:把 SQL 結構與數值分開,防止外來值改變指令結構。
- 最少數據與一般錯誤:減少一旦出錯時可被洩露的內容。
- 把輸入過濾與輸出編碼視為同一件事,或只在其中一處處理。
- 用字串拼接建立含外來數據的 SQL,而沒有使用參數化查詢。
- 收集與功能無關的個人數據,或把完整內部資料輸出到頁面。
- 直接顯示數據庫錯誤、檔案路徑、設定值或堆疊追蹤。
安全控制必須配合數據所處位置
防禦性安全不是在表單加上一項檢查便完成,而是由接收輸入開始,一直延伸至權限判斷、數據庫存取、畫面輸出及錯誤處理。客戶端檢查可改善界面,但伺服器端仍要按存在、類型、範圍、格式、長度及白名單等規則作有效性檢驗,並確認目前用戶有權執行操作。
不同防護處理不同問題。參數化查詢把 SQL 結構與外來數值分開,適用於數據庫操作;輸出編碼則在資料進入 HTML、屬性或其他輸出情境前轉換特殊字符,以降低 XSS 風險。兩者不能互相取代,也不應只依賴一個通用「清理」函數。
系統應遵守最少數據原則,只收集、保存及顯示完成任務所必需的內容。錯誤發生時,對用戶提供可採取行動但不洩露內部結構的訊息;詳細 SQL、檔案路徑及堆疊追蹤應記錄於受保護的伺服器日誌,而不是直接顯示在網頁。
表單安全:以白名單有效性檢驗為核心
前端可提供下拉式選單限制輸入,但用戶仍可自行構造請求提交未列於選單的值。
因此伺服器端應把可接受的值列入「允許清單」,並以 in_array() 等方法檢查;不符合即拒絕處理。
XSS 基本概念:為何要做輸出前處理?
若把用戶輸入直接輸出到網頁,輸入內容可能被瀏覽器當作 HTML/JavaScript 解讀,造成跨網站腳本攻擊(XSS)。
基本防線是:在輸出前使用 htmlspecialchars() 把特殊字元轉換為安全形式。
錯誤訊息設計:既要清楚,又要避免洩露細節
- 給用戶看的訊息:指出哪個欄位不符合要求,以及如何修正(例如「密碼最少 8 字元」)。
- 避免洩露:不要直接輸出伺服器路徑、數據庫錯誤全文、或系統堆疊追蹤。
- 給開發者看的細節:可記錄到伺服器日誌(本課程先理解概念即可)。
Checkpoint:延伸課題(≥40 題)
本小測以四選一為主,涵蓋:白名單驗證、輸出前處理(XSS 概念)、以及錯誤訊息的設計原則。
✍️頁末 20 題 Coding(一行一題)
每題均提供:提示/核對答案/顯示參考答案/講解。請在模擬器內完成代碼,然後按「核對答案」。
代碼題 1:表單(text):問候語
代碼題 2:表單(password):只顯示密碼長度
代碼題 3:表單(date):輸出生日
代碼題 4:下拉式選單:顯示班別
代碼題 5:複選框:列出興趣(foreach)
代碼題 6:GET 搜尋:從 URL 取得 q
代碼題 7:POST 登入:必填檢查
代碼題 8:isset():欄位是否存在
代碼題 9:empty():必填欄位
代碼題 10:is_numeric():年齡必須為數字
代碼題 11:strlen():密碼最少 8 字元
代碼題 12:in_array():白名單驗證下拉值
代碼題 13:strpos():電郵必須包含 @
代碼題 14:曲奇:記住使用者名稱 1 天
代碼題 15:曲奇:清除指定 cookie
代碼題 16:Session:登入後建立已登入狀態
代碼題 17:Session:未登入則導回登入頁
代碼題 18:登出:清除 Session
代碼題 19:同一處理邏輯支援 GET/POST
代碼題 20:綜合:提交→有效性檢驗→成功才設定 Session
總結 課文腦圖總結
重點:
- 表單只會提交具有
name的控制項;id、class與label for有不同用途。 - GET 適合可分享的讀取與搜尋;POST 適合登入及會改變狀態的操作,但 POST 本身並不等於加密。
- 伺服器端有效性檢驗應按「存在 → 結構 → 必填 → 類型/格式 → 長度/範圍 → 允許清單」逐層進行。
- 曲奇適合少量非敏感偏好;登入及權限狀態應由伺服器端 Session 保存,輸出任何外來值前仍要安全轉義。
有效性檢驗限制輸入規格;htmlspecialchars() 處理 HTML 輸出;Session 及授權檢查決定用戶可否進入頁面或執行操作。
曲奇內容在瀏覽器,容易被改動或清除;Session 資料在伺服器,瀏覽器通常只保存 Session ID。兩者會在狀態管理中互相配合。
函數節點列出回傳值、用途及常見陷阱;代碼題節點則展示表單、GET/POST、曲奇及 Session 的完整應用。
本腦圖把全課重新分類為「數據生命週期、表單控制項、GET/POST、有效性檢驗、函數陷阱、安全輸出、曲奇、Session 及整合應用」,並非照搬原網頁章節次序。
閱讀時可先從根節點展開完整流程,再利用「樹狀圖導覽」直接跳到 strpos() 的 0/false 陷阱、曲奇屬性、Session 登入流程或任何代碼題。
聚焦模式會以動畫移到所選節點並調整縮放;所有學生修改只暫存在瀏覽器本機,亦可匯出為 .ictmap。