[研究]ASP.NET WebForm 網站用 OWASP ZAP 2.16.1 掃描發現【Absence of Anti-CSRF Tokens】弱點,該如何解 ?
2025-07-08
環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 20
********************************************************************************
證據: <form name="aspnetForm" method="post" action="./Login.aspx" id="aspnetForm">
來源: 被動 (10202 - Absence of Anti-CSRF Tokens)
說明: No Anti-CSRF tokens were found in a HTML submission form.
A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a web site has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has for a web site. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.
CSRF attacks are effective in a number of situations, including:
* The victim has an active session on the target site.
* The victim is authenticated via HTTP auth on the target site.
* The victim is on the same local network as the target site.
CSRF has primarily been used to perform an action against a target site using the victim's privileges, but recent techniques have been discovered to disclose information by gaining access to the response. The risk of information disclosure is dramatically increased when the target site is vulnerable to XSS, because XSS can be used as a platform for CSRF, allowing the attack to operate within the bounds of the same-origin policy.
解決方案
Phase: Architecture and Design
Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
For example, use anti-CSRF packages such as the OWASP CSRFGuard.
Phase: Implementation
Ensure that your application is free of cross-site scripting issues, because most CSRF defenses can be bypassed using attacker-controlled script.
Phase: Architecture and Design
Generate a unique nonce for each form, place the nonce into the form, and verify the nonce upon receipt of the form. Be sure that the nonce is not predictable (CWE-330).
Note that this can be bypassed using XSS.
Identify especially dangerous operations. When the user performs a dangerous operation, send a separate confirmation request to ensure that the user intended to perform that operation.
Note that this can be bypassed using XSS.
Use the ESAPI Session Management control.
This control includes a component for CSRF.
Do not use the GET method for any request that triggers a state change.
Phase: Implementation
Check the HTTP Referer header to see if the request originated from an expected page. This could break legitimate functionality, because users or proxies may have disabled sending the Referer for privacy reasons.
********************************************************************************
ChatGPT 說:
針對 ASP.NET WebForm 被 OWASP ZAP 2.16.1 掃描發現「Absence of Anti-CSRF Tokens」弱點,具體解決方法如下:
一、背景說明
此弱點表示:
- 你的 <form> 沒有包含防止 CSRF(跨站請求偽造)的 Token。
- ASP.NET WebForms 預設沒有內建 CSRF 保護,必須自行實作。
二、標準解法 — 手動實作 Anti-CSRF Token
你可以參考以下方式為 WebForm 網站加上 Anti-CSRF:
1. 產生 CSRF Token
在 Page_Load 事件內,若為第一次載入頁面,產生 Token 並儲存在 Session,再寫入隱藏欄位:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string csrfToken = Guid.NewGuid().ToString();
Session["CSRFToken"] = csrfToken;
hiddenCsrfToken.Value = csrfToken;
}
}
|
2. 前端 <form> 加入隱藏欄位
你的 .aspx 頁面:
<form id="aspnetForm" runat="server">
<asp:HiddenField ID="hiddenCsrfToken" runat="server" />
<!-- 其他表單內容 -->
<asp:Button ID="btnSubmit" runat="server" Text="送出" OnClick="btnSubmit_Click" />
</form>
|
3. 驗證 CSRF Token
在伺服器端驗證:
protected void btnSubmit_Click(object sender, EventArgs e)
{
string postedToken = hiddenCsrfToken.Value;
string sessionToken = Session["CSRFToken"] as string;
if (string.IsNullOrEmpty(postedToken) || postedToken != sessionToken)
{
// 驗證失敗,拒絕請求
Response.StatusCode = 403;
Response.End();
}
// 驗證通過,處理正常流程
}
|
三、進階建議
- Token 重新產生:驗證成功後可重新產生 Token 以防重放攻擊。
- Token 儲存方式:使用 Session、ViewState 或 HttpOnly Cookie 組合提升安全性。
- 避免 XSS:CSRF 防禦易被 XSS 攻擊繞過,請先確保網站無其他 XSS 弱點。
四、其他方案
1. 使用 OWASP CSRFGuard
- 官方推薦使用 OWASP CSRFGuard,但 ASP.NET 原生支援不佳,需額外整合。
- 若不想自製,可考慮 ASP.NET MVC 或 .NET Core 這類內建 CSRF 防禦的框架。
2. 驗證 Referer 或 Origin
可以額外驗證 Request.UrlReferrer,但不可靠,容易因瀏覽器、代理設定導致判斷失準。
if (Request.UrlReferrer == null || !Request.UrlReferrer.Host.Equals(Request.Url.Host, StringComparison.OrdinalIgnoreCase))
{
Response.StatusCode = 403;
Response.End();
}
|
五、結論
針對 WebForm:
- ✅ 必須自行在每個重要 <form> 加入 Anti-CSRF Token。
- ✅ 伺服器端驗證 Token 與 Session 是否匹配。
- ✅ 減少 GET 觸發狀態變更操作。
- ✅ 確保無其他 XSS 弱點。
這樣即可通過 OWASP ZAP 對「Absence of Anti-CSRF Tokens」的檢測。
********************************************************************************
若為使用 MasterPage 的 ASP.NET WebForm 網站,且 <form id="form1" runat="server"> 在 MasterPage 中,但 button 不在 MasterPage 中,上面程式如何改 ?
ChatGPT 說:
✅ 一、MasterPage (Site.Master)
MasterPage 中 <form> 只能有一個。請加上隱藏欄位:
<form id="form1" runat="server">
<asp:HiddenField ID="hiddenCsrfToken" runat="server" />
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</form>
|
✅ 二、Content Page (Login.aspx + Login.aspx.cs)
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string csrfToken = Guid.NewGuid().ToString();
Session["CSRFToken"] = csrfToken;
// 從 MasterPage 尋找 HiddenField 並設定值
HiddenField hiddenToken = (HiddenField)Master.FindControl("hiddenCsrfToken");
if (hiddenToken != null)
{
hiddenToken.Value = csrfToken;
}
}
} |
protected void btnLogin_Click(object sender, EventArgs e)
{
string postedToken = "";
string sessionToken = Session["CSRFToken"] as string;
// 取出 MasterPage 中的 HiddenField
HiddenField hiddenToken = (HiddenField)Master.FindControl("hiddenCsrfToken");
if (hiddenToken != null)
{
postedToken = hiddenToken.Value;
}
if (string.IsNullOrEmpty(postedToken) || postedToken != sessionToken)
{
// 驗證失敗,封鎖請求
Response.StatusCode = 403;
Response.End();
return;
}
// 驗證成功,執行登入流程
}
|
✅ 三、可選擇改成 ViewStateUserKey
ASP.NET 內建 CSRF 防禦之一是設定 ViewStateUserKey,但它只能保護 ViewState,不保護 <form> 自己送出的資料。建議與上述 Token 一起使用:
protected void Page_Init(object sender, EventArgs e)
{
if (Session["SessionID"] == null)
Session["SessionID"] = Guid.NewGuid().ToString();
this.ViewStateUserKey = Session["SessionID"].ToString();
}
|
*******************************************************************************
(完)
相關

沒有留言:
張貼留言