程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> 關於ASP.NET >> 啟用和自定義 ASP.NET Web API 服務的安全性

啟用和自定義 ASP.NET Web API 服務的安全性

編輯:關於ASP.NET

對於最常見的場景 — Web 頁面中的 JavaScript 訪問同一站點上的 Web API 服務,討論 ASP.NET Web API 的安全性幾乎是多余的。如果對用戶執行身份驗證和授權對 Web 窗體/視圖(包含使用服務的 JavaScript)的訪問均已設置,則服務可能已具備其所需的所有安全性了。這要歸因於 ASP.NET,它會將其用 於驗證頁面請求的 Cookie 和身份驗證信息作為對服務方法的任意客戶端 JavaScript 請求的一部分進行發送 。但有一個非常重要的例外: ASP.NET 無法自動防御跨站點請求偽造 (CSRF/XSRF) 攻擊(稍後詳述)。

除 CSRF 以外,還有兩個值得探討 Web API 服務保護的場景。第一個場景是當服務的使用方為客戶端,而 非與 ApiControllers 處於同一個站點上的頁面時。這些客戶端可能未經過窗體身份驗證的審核,也可能未獲 取 ASP.NET 用於控制服務訪問的 Cookie 和令牌。

第二個場景是需要為服務添加超出 ASP.NET 安全功能范圍的身份驗證時。ASP.NET 提供的默認身份驗證基 於在身份驗證期間 ASP.NET 分配給請求的標識。您可能希望擴展該標識,以授權進行基於標識名稱或角色以 外條件的訪問。

Web API 提供了多種選擇,以應對這兩種場景。事實上,我將討論的是接受 Web API 請求上下文的安全性 ,但由於 Web API 與 Web 窗體和 MVC 均以 ASP.NET 為基礎,因而了解 Web 窗體或 MVC 安全性的讀者一定 會非常熟悉本文中介紹的工具。

有一點需要特別注意: 雖然 Web API 提供了多種身份驗證和授權選項,但安全始於主機(IIS 或進行自 托管時創建的主機)。例如,如果需要確保 Web API 服務與客戶端之間通信的隱秘性,則至少應開啟 SSL。 但這是站點管理員而非開發者的職責。在本文中,我將忽略主機方面的內容,專注於開發者能夠/應該為確保 Web API 服務的安全而進行的工作(無論 SSL 開啟與否,我討論的這些工具都能正常工作)。

抵御跨站點請求偽造攻擊

當用戶訪問使用窗體身份驗證的 ASP.NET 網站時,ASP.NET 會生成一個 Cookie,表明該用戶已經過身份 驗證。浏覽器會在每次向該站點發出後續請求時發送該 Cookie,而不管請求來自何處。只要會導致浏覽器自 動發送之前收到的身份驗證信息的任意身份驗證方案存在,您的站點就有可能成為 CSRF 的攻擊目標。在站點 向浏覽器提供安全 Cookie 後,如果用戶訪問了某個惡意站點,該站點即可向您的服務發送請求,利用浏覽器 之前收到的身份驗證 Cookie 發動攻擊。

為抵御 CSRF 攻擊,需要在服務器端生成防偽令牌,並將之嵌入到要在客戶端調用中使用的頁面中。 Microsoft 提供了 AntiForgery 類及一個 GetToken 方法(可生成特定於發出請求的用戶的令牌,當然,此 處的用戶可以為匿名用戶)。下面的代碼生成了兩個令牌,並將之嵌入至可在 View 中使用的 ASP.NET MVC ViewBag:

          [Authorize(Roles="manager")]
public ActionResult Index()
{
  string cookieToken;
  string formToken;
  AntiForgery.GetTokens(null, out cookieToken, out formToken);
  ViewBag.cookieToken = cookieToken;
  ViewBag.formToken = formToken;
  return View("Index");
}

針對服務器的任意 JavaScript 調用都需要將該令牌作為請求的一部分予以返回(CSRF 站點沒有 此類令牌,也就無法返回它們)。下面的代碼(位於 View 中)將動態生成一個將令牌加入請求標題中的 JavaScript 調用:

        $.ajax("http://phvis.com/api/Customers",{
type: "get",
contentType: "application/json",
headers: {
  'formToken': '@ViewBag.formToken',
  'cookieToken': '@ViewBag.cookieToken' }});

一個稍微復雜點的解決方案是將令牌嵌入至 View 中的隱藏字段,使得這段 JavaScript 代碼不會太引人注目。該過程的第一步是將令牌添加到 ViewData 字典 中:

          ViewData["cookieToken"] = cookieToken;
ViewData["formToken"] = formToken;
接下來,在 View 中將數據嵌入至隱藏字段。使用 

HtmlHelper 的 Hidden 方法時,只需傳遞 ViewDate 中的某個鍵值,以生成正確的輸入標記:
@Html.Hidden("formToken")

生成的輸入標記將使用 ViewData 鍵作為標記的名稱和 ID 屬性 ,並將從 ViewData 字典檢索到的數據放入標記的值屬性中。之前代碼生成的輸入標記將如下所示:

<input id="formToken" name="formToken" type="hidden" value="...token..." />

之後,即可用 JavaScript 代碼(跟 View 保存在不同的文件中)從輸入標記中檢索值並在 ajax 調用中使用 它們:

        $.ajax("http://localhost:49226/api/Customers", {
type: "get",
contentType: "application/json",
headers: {
  'formToken': $("#formToken").val(),
  'cookieToken': $("#cookieToken").val()}});

在 ASP.NET Web 窗體中,通過使用 ClientScriptManager 對象(可從 Page 的 ClientScript 屬性檢索)的 RegisterClientScriptBlock 方法 插入包含嵌入式令牌的 JavaScript 代碼,也可達到同一目的。

          string CodeString = "function CallService(){" +
  "$.ajax('http://phvis.com/api/Customers',{" +
  "type: 'get', contentType: 'application/json'," +
  "headers: {'formToken': '" & formToken & "',” +
  "'cookieToken': '" & cookieToken & "'}});}"
this.ClientScript.RegisterClientScriptBlock(
  typeOf(this), "loadCustid", CodeString, true);

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved