JSP 本質是 Servlet,編譯執行效率高,但若忽視安全細節,極易造成嚴重漏洞。本文從六大實戰場景切入,示範錯誤寫法與修正方案,助你建立「安全左移」思維。
錯誤:僅在主管理頁 user_manager.jsp 檢查 Session,子功能頁 modifyuser_manager.jsp 直接信任參數 modifyid,導致越權查看/修改任意用戶資料(含明文密碼)。
修正:每個 需權限的 JSP/Action 開頭統一檢查:
if (session.getAttribute("UserName") == null ||
!"系統管理員".equals(session.getAttribute("UserClass"))) {
response.sendRedirect("err.jsp?id=14"); return;
}
或採用 Filter 統一攔截,避免漏網之魚。
property="*" 慎用場景:購物車 Bean 有 balance(金額)屬性,表單提交 newItem=xxx,惡意用戶在 Query String 加 &balance=0。
後果:<jsp:setProperty name="cart" property="*" /> 會將 balance=0 寫入 Bean,結帳時金額歸零。
對策:明確列出允許綁定的屬性,或在 Bean setter 內驗證業務規則,絕不盲目 property="*"。
攻擊向量:?name=test<script>alert(document.cookie)</script> 若直接 out.println(name),腳本在受害者瀏覽器執行,竊取 Cookie、重導向釣魚站。
防禦兩層:
str.matches("[a-zA-Z0-9]+") 僅允許預期字元。<c:out value="${name}" /> 自動 HTML Entity 編碼,或手工替換 <>"'&。高風險寫法:
String sql = "SELECT * FROM login WHERE user='" + userName + "' AND pwd='" + userPwd + "'";
Payload:user=jack&pwd=' OR '1'='1 → 條件永真,繞過驗證。
唯一正解:PreparedStatement + 參數綁定:
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM login WHERE user=? AND pwd=?");
ps.setString(1, userName);
ps.setString(2, userPwd);
資料庫驅動會將參數視為純資料,徹底斷開 SQL 結構與使用者輸入。
String pwd = request.getParameter("pwd"); 產生的字串在 GC 前常駐 Heap,甚至被 Swap 到磁碟,遭記憶體掃描工具竊取。
緩解:使用 char[] 接收密碼(如 request.getParameterValues("pwd")[0].toCharArray()),驗證後立即 Arrays.fill(pwd, '\0') 清零。注意:標準 Servlet API 仍回傳 String,完整解決需容器層面支援(如 Tomcat 的 PasswordMask)。
問題:類別層級 int count; 被多執行緒同時 count++,導致計數錯誤;或 Connection 實例變數被併發使用。
方案優先序:
synchronized(lock){ ... } 鎖住關鍵區段。<%@ page isThreadSafe="false" %> 強制單執行緒,**嚴重影響並發效能,僅作最後手段**。property="*"