這篇文章主要介紹在ASP.NET MVC應用程式中如何防止JavaScript注入攻擊。這篇文章討論了兩種防止JavaScript攻擊的方法:
在顯示資料的時候,通過使用Encoding來防止攻擊
在接收到資料的時候,通過使用Encoding防止攻
一、什麼是JavaScript注入攻擊(原創:灰灰蟲的家 http://hi.baidu.com/grayworm)
在我們接收使用者輸入或在頁面顯示使用者輸入的資料時,我們的網站預設是向JavaScript注入攻擊敞開了大門。讓我們看看我們的Web應用程式如何被JavaScript攻擊。
假設我們建立了一個使用者反饋的網站,使用者可以訪問該網站並填寫產品使用的反饋資訊。當使用者填寫完反饋資訊後,程式會把使用者的反饋資訊顯示在頁面上。
《圖1 》
使用者反饋網站的控制器代碼如下所示,其中包含兩個動作Index()和Create()
Listing 1 – HomeController.cs
using System;
using System.Web.Mvc;
using CustomerFeedback.Models;
namespace CustomerFeedback.Controllers
{
[HandleError]
public class HomeController : Controller
{
private FeedbackDataContext db = new FeedbackDataContext();
public ActionResult Index()
{
return View(db.Feedbacks);
}
public ActionResult Create(string message)
{
// Add feedback
var newFeedback = new Feedback();
newFeedback.Message = message;
newFeedback.EntryDate = DateTime.Now;
db.Feedbacks.InsertOnSubmit(newFeedback);
db.SubmitChanges();
// Redirect
return RedirectToAction("Index");
}
}
}
Index()方法用來向視圖傳遞顯示資料的,這個方法檢索表中所有的使用者反饋資訊,並傳遞給頁面顯示。
Create()建立一個新的使用者返回,並把它加到資料庫中。使用者在表單中輸入的資料會以message參數被傳遞到Create()方法中。我們通過調用DataContext.SubmitChanges()方法把頁面返回資料送到資料庫中去。最後調用Index()動作,顯示所有的使用者反饋資料。
Index視圖代碼如下
Listing 2 – Index.aspx
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="CustomerFeedback.Views.Home.Index"%>
<%@ Import Namespace="CustomerFeedback.Models" %>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h1>Customer Feedback</h1>
<p>Please use the following form to enter feedback about our product.</p>
<form method="post" action="/Home/Create">
<label for="message">Message:</label>
<br />
<textarea name="message" cols="50" rows="2"></textarea>
<br /><br />
<input type="submit" value="Submit Feedback" />
</form>
<% foreach (Feedback feedback in ViewData.Model) {%>
<p>
<%=feedback.EntryDate.ToShortTimeString()%>--<%=feedback.Message%>
</p>
<% }%>
</asp:Content>
Index視圖代碼可以分成兩部分來看待,上面的部分是使用者輸入的表單,下面的部分是foreach…loop迴圈,迭代所有的使用者返饋資訊,顯示EntryDate和Message兩個欄位的資訊。
使用者返饋網站很簡單,但這個網站很容易被JavaScript攻擊。
如果使用者輸入的反饋內容是
<script>alert(“Boo!”)</script>
那這段文本在顯示的時候會在頁面上彈出一個訊息框,以後任何人在訪問這個網站的時候,在顯示使用者的反饋資訊時都會彈出這個對話方塊。
《圖2》
可能你對上面的JavaScript注入感覺沒什麼大不了的,好像它只能對我們的介面顯示產生影響,它並不會給我們的網站的安全性還來真正可怕的影響。不幸的是,一個駭客足可以使用JavaScript攻擊來給你的網站帶來可怕的事情。它可以使用JavaScript注入執行Cross-Site Scripting攻擊。Cross-Site Scripting攻擊就是盜竊用來的機密資訊並發送到別的網站上去。比如:駭客可以使用JavaScript注入攻擊從客戶機的Cookie中盜取敏感資訊(密碼、信用卡號、社保帳號等),或者把其它使用者表單中輸入的機密資料發送到其它網站上去。
二、解決方案一:在視圖中使用Html.Encode顯示資料(原創:灰灰蟲的家 http://hi.baidu.com/grayworm)
防止JavaScript注入攻擊的一個簡單方法就是當顯示使用者輸入的資料時,使用Html.Encode()方法把資料庫中的資料編碼顯示。我們修改後的Index視圖代碼如下:
Listing 3 – Index.aspx (HTML Encoded)
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="CustomerFeedback.Views.Home.Index"%>
<%@ Import Namespace="CustomerFeedback.Models" %>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h1>Customer Feedback</h1>
<p>Please use the following form to enter feedback about our product. </p>
<form method="post" action="/Home/Create">
<label for="message">Message:</label>
<br />
<textarea name="message" cols="50" rows="2"></textarea>
<br /><br />
<input type="submit" value="Submit Feedback" />
</form>
<% foreach (Feedback feedback in ViewData.Model) {%>
<p>
<%=feedback.EntryDate.ToShortTimeString()%>--<%=Html.Encode(feedback.Message)%>
</p>
<% }%>
</asp:Content>
我們注意到,在上面的代碼中,我們把feedback.Message資訊使用Html.Encode()方法進行了編碼。
<%=Html.Encode(feedback.Message)%>
HTML Encode的意思就是,把一些危險的字元如<和>替換為<和>。所以當<script>alert("Boo!")</script>被Encode後,就會變為<script>alert("Boo!")</script>。被編碼後的字串就不再是一個可執行檔JavaScript代碼了,它會正常顯示在頁面上。如所示
《圖3》
上面的代碼中我們只對feedback.Message進行了編碼,而feedback.EntryDate沒有進行編碼。因為feedback.EntryDate是控制器產生的,不會有危險性,而feedback.Message是使用者輸入的,所以為了安全其見我們需要對其進行編碼
三、解決方案二:在控制器中對HTML資料進行編碼(原創:灰灰蟲的家 http://hi.baidu.com/grayworm)
除了在顯示的時候對使用者反饋的資訊進行編碼顯示,我們還可以在控制器接收到使用者提交的資料後進行編碼,然後把編碼後的資料送到資料庫中。
下面的代碼,是我們在控制器中對使用者輸入的資料進行編碼
Listing 4 – HomeController.cs (HTML Encoded)
using System;
using System.Web.Mvc;
using CustomerFeedback.Models;
namespace CustomerFeedback.Controllers
{
[HandleError]
public class HomeController : Controller
{
private FeedbackDataContext db = new FeedbackDataContext();
public ActionResult Index()
{
return View(db.Feedbacks);
}
public ActionResult Create(string message)
{
// Add feedback
var newFeedback = new Feedback();
newFeedback.Message = Server.HtmlEncode(message);
newFeedback.EntryDate = DateTime.Now;
db.Feedbacks.InsertOnSubmit(newFeedback);
db.SubmitChanges();
// Redirect
return RedirectToAction("Index");
}
}
}
從上面的代碼中我們看出,Create()動作在向資料庫插入資料之前,對使用者輸入的資料進行編碼。當在介面中顯示資料庫資料的時候,使用者的輸入已經被編碼了,就不會造成危險。
一般我們更推薦上面討論的第一種解決方案,因為第二種方案會在資料庫產生編碼後的HTML標記,即會產生一些古怪難以理解的資料,這些資料在WEB頁面中顯示會變得正常,但在WinForms應用程式中顯示時會搞成一團糟。
總結
這篇文章主要討論了JavaScript攻擊,並提出在ASP.NET MVC應用程式中兩種解決方案:
在顯示資料的時候,通過使用Encoding來防止攻擊
在接收到資料的時候,通過使用Encoding防止攻