.NET Core CSRF 防範機制遇上 AJAX
- 2020-06-19
- 16147
- 0
從 .NET Framework 時代的 ASP.NET MVC 就有內建防範 CSRF 的機制,這機制在 MVC 架構下開發者可自由的選擇啟用或關閉,但是 .NET Core 發行時新推出的 RazorPage 則是預設開啟了 CSRF 防範機制,現在的網路環境越來越危險了預設開啟是非常正確的選擇,但是這樣的預設啟用對於初級的開發者來說就會很挫折,為什麼一個 AJAX 都寫不好呢。
雖然說官方文件都有,但開發人員不看文件的比例和不寫文件差不多,所以我還是寫一篇來記錄一下吧
基本的 AJAX
首先來做一個基本的 HTML 用於稍等的 AJAX 應用。
<div class="text-center">
<h1 class="display-4">SkillTree</h1>
<div>
<input id="a" name="a" value="test"/>
<button type="button" data-url="@Url.Action("index")">Go</button>
</div>
</div>
稍微注意的是上面的 HTML 並沒有 Form 標籤,而那個 Button 也真的是 Button ,實際的表單送出完全要依賴 AJAX 處理,下方就是範例 Code
<script>
$(function() {
$("[data-url]").on("click", function () {
let targetUrl = $(this).data("url");
$.ajax({
type: "POST",
url: targetUrl,
data: "q="+$("#a").val(),
dataType: "json",
success: function (response) {
alert(response.test);
}
});
});
});
</script>
當使用者按下 Go 按鈕就會觸發上述這段 Code 而把表單資料往 Controller 送
[HttpPost]
public IActionResult Index(string q)
{
return Json(new
{
test=q
});
}
執行後就會一切順利,本篇就可以結束了😏
包含 CSRF 防範的 AJAX
開頭有提到,MVC 架構下開發者可自由的選擇啟用或關閉(預設是關閉)所以剛剛的 Code 一切都正常,但當我們明確的加上 [ValidateAntiForgeryToken]
啟用 CSRF 防範機制後(Razor Page 預設就開啟防範機制)
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(string q)
{
return Json(new
{
test=q
});
}
一切都不同了,原本正常的程式,怎麼按都只能收到 400 的回應😱
為了安全,千萬絕對不可以閉上眼睛關閉驗證!
解決方式是首先要先讓頁面可以產生 Anti Forgery Token ,產生的 Code 都已經包裝在 @Html.AntiForgeryToken()
Html Helper 內,直接使用即可,所以一開始的 HTML 變成這樣
<div class="text-center">
<h1 class="display-4">SkillTree</h1>
<div>
<input id="a" name="a" value="test"/>
<button type="button" data-url="@Url.Action("index")">Go</button>
</div>
</div>
@Html.AntiForgeryToken()
然後再把呼叫的 javascript 調整一下
<script>
$(function() {
$("[data-url]").on("click", function () {
let targetUrl = $(this).data("url");
$.ajax({
type: "POST",
url: targetUrl,
data: "q="+$("#a").val(),
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("requestverificationtoken",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (response) {
alert(response.test);
}
});
});
});
</script>
網路有很多範例會需要加上 services.AddAntiforgery(o => o.HeaderName = "CSRFTOKEN");
來調整 token 的名稱,但 demo 是推薦直接使用 requestverificationtoken
這樣就啥都不用再調了。
以上的解法也可使用在 Razor Page 內。
回應討論