本文章是由機器翻譯。

ASP.NET

ASP.NET Web API 安全性篩選器

Badrinarayanan Lakshmiraghavan

身份驗證和授權是安全的應用程式的基石。身份驗證建立使用者的身份驗證,同時授權決定是否允許使用者執行請求的操作提供的憑據。有擔保的 Web API 對請求進行身份驗證和授權訪問請求的資源的基礎建立的身份。

ASP.NETWeb API 使用在ASP.NETWeb API 管線中,可用的擴充點,以及使用由宿主提供的選項中,您可以實現身份驗證。與ASP.NETWeb API 的第一個版本,常見的做法是使用授權篩選器或操作篩選器來實現身份驗證。ASP.NETWeb API 2 介紹了一種新的身份驗證濾波器,致力於這一進程。這種新的可擴充性點允許身份驗證和授權的關切,以清晰的分離開來。在這篇文章,我要向您介紹這些兩個安全篩選器並向您展示如何使用它們來實現身份驗證和授權作為單獨的關注ASP.NETWeb API 中。

為實現安全方面的選項

可以使用提供的主機,以及那些在ASP.NETWeb API 管道本身中可用的可擴充性點實現身份驗證和授權ASP.NETWeb API 中。基於主機的選項包括 HTTP 模組和浩然中介軟體元件,而ASP.NETWeb API 可擴充性選項包括的訊息處理常式、 操作篩選器、 授權篩選器和身份驗證篩選器。

基於主機的選項很好融入東道國管道,並有能力拒絕早些時候管道中的無效請求。ASP.NETWeb API 可擴充性選項,另一方面,提供更細的級別的身份驗證過程的控制權。那就是,你將能夠為不同的控制器和甚至不同的操作方法設置不同的身份驗證機制。代價是更好的集成,與東道國和早期急性排斥反應的錯誤的請求,與身份驗證細微性。除了這些一般性的特點,每個選項有其自身的優點和缺點,我將在以下各節將介紹。

HTTP 模組這是一個為在 IIS 上運行的 Web Api 的選項。HTTP 模組允許安全代碼執行早期作為 IIS 管道的一部分。建立了從 HTTP 模組主要是提供給所有元件包括運行後在管道中的 IIS 元件。例如,當校長由 HTTP 模組對 AuthenticateRequest 事件作出回應,校長的使用者名獲取正確記錄在 IIS 日誌中的 cs 使用者名欄位中。HTTP 模組的最大缺點是細微性的缺乏。HTTP 模組運行進入應用程式的所有請求。Web 應用程式具有不同的功能,如 HTML 生成標記、 Web Api 等等,有一個強制執行的一種方法中的身份驗證的 HTTP 模組通常不是足夠靈活的方法。使用 HTTP 模組的另一個缺點是在主機上的依賴 — — 非法入境者,在這種情況下。

歐文真中介軟體這是另一個主機相關選項,可用與浩然的主機。ASP.NETWeb API 2 完全支援浩然。也許最令人信服的理由,為了安全使用,浩然中介軟體是同一中介軟體能夠跨越不同的框架。這意味著您可以使用多個框架,如ASP.NETWeb API,那麼 SignalR 在您的應用程式,但是使用通用安全中介軟體。然而,浩然中介軟體的最小細微性可能是一個缺點,因為浩然中介軟體在浩然管道運行並獲取調用通常對於所有的請求。此外,浩然中介軟體可以僅用浩然相容主機,雖然這種依賴性是比依賴以一個特定的主機/伺服器如 IIS),比較好的正如 HTTP 模組為例。有一點值得注意這裡是浩然中介軟體可以在 (IIS 集成)ASP.NET管道,由於 Microsoft.Owin.Host.SystemWeb 包中運行。

訊息處理常式可擴充性選項提供由ASP.NETWeb API 中使用訊息處理常式,因為安全是它的最大好處是ASP.NETWeb API 框架的概念,並因此,並不取決於底層的主機或伺服器。此外,訊息處理常式只運行 Web API 發出的請求。使用訊息處理常式的缺點是控制的缺乏更精細。訊息處理常式可以配置為運行作為一個全球的處理常式,用於所有的請求,或者為 a 的特定路由。對於給定的路線,你可以有多個控制器。所有這些控制器和它們包含的行動方法必須共用相同的身份驗證由該路由配置訊息處理常式強制執行。換句話說,由一個訊息處理常式實現的身份驗證的最低細微性是在工藝路線級別。

操作篩選器ASP.NETWeb API 提供的另一個可擴充性選項是操作篩選器。但是,從執行身份驗證的角度來看,它不是一個可行的選擇只是因為它運行後授權篩選器運行在ASP.NETWeb API 管道。身份驗證身份驗證和授權才能正常工作,必須在授權之前。

授權篩選器ASP.NETWeb API 提供的另一種可擴充性選項卻授權篩選器。實施自訂身份驗證方案需要更多的細微性比訊息處理常式可以提供最常用的方法之一是使用授權篩選器。使用身份驗證和授權的授權篩選器中的主要問題是執行授權篩選器的順序並不保證由ASP.NETWeb API。基本上,這意味著您授權篩選器執行授權能很好運行之前您的授權篩選器執行身份驗證可以運行,使授權篩選器選項同樣不適用於身份驗證,正如操作篩選器選項。

身份驗證篩選器協調點的這篇文章,這是最新的可擴充性選項可用,在ASP.NETWeb API 2。 身份驗證篩選器運行後訊息處理常式,但在所有其他篩選器類型之前。因此,它們為執行身份驗證的關注更好的選擇。最重要的是,身份驗證篩選器在授權篩選器之前運行。通過使用一個篩選器,專門針對使用身份驗證或授權,你可以單獨的身份驗證和授權問題。

此外,身份驗證篩選器提供控制項或使它們特別有用的細微性的級別。以旨在由本機移動應用程式和基於瀏覽器的 AJAX 應用程式使用的 Web API 為例。移動應用程式可能會出現一個權杖授權 HTTP 標頭中,而 AJAX 應用程式可能使用的身份驗證 cookie 作為憑據。進一步,假設 API 的子集是敏感和僅適用于本機的移動應用程式,並且您想要確保只憑一個權杖和不 (cookie 是容易受到跨網站請求偽造 [XSRF],雖然 HTTP 授權標頭中的標記不是) 一個 cookie 訪問行動方法。在這種情況下,身份驗證必須發生在更細細微性比用一個基於主機的選項或甚至是一個訊息處理常式是可能的級別。身份驗證篩選器非常適合這一使用情形。您可以應用基於對所有這些控制器或操作方法,它們必須使用身份驗證篩選器基於 cookie 中其他地方權杖的身份驗證篩選器。假設,在此場景中,你有幾個共同的操作方法,而且您希望他們可以通過一個權杖或 cookie 訪問。您只可以對這些常見的操作方法應用 cookie 和權杖身份驗證篩選器和篩選器之一將能夠成功進行身份驗證。這種控制就是最大的價值身份驗證篩選器給表。當顆粒控制身份驗證是必需的時正確的做法是執行身份驗證通過驗證篩選器和授權通過授權篩選器方面的憂慮。

它這裡值得一提的預置身份驗證篩選器,HostAuthenticationFilter,使通過浩然中介軟體ASP.NETWeb API 認證。雖然浩然身份驗證中介軟體在管道中運行,並且試圖"積極主動"對傳入的請求進行身份驗證,它還可以配置為"被動,"驗證該請求,只有當問。HostAuthenticationFilter 後來在 Web API 管道允許運行的被動浩然身份驗證中介軟體的名字。此方法允許可以在框架 (包括 Microsoft 提供的浩然身份驗證中介軟體) 之間共用的身份驗證代碼,同時仍然允許進行身份驗證的每個行動細微性。

雖然您可以混合使用更細細微性的 Web API 管道基於身份驗證主機分級身份驗證,您必須仔細考慮如何主機分級的身份驗證可以影響 Web API 認證。例如,您可以基於 cookie 的身份驗證中介軟體在主機分級旨在用於與其他框架,說ASP.NETMVC,但讓 Web API 使用基於 cookie 的主要使它容易受到攻擊,如 XSRF。為了説明在這種情況下,SuppressDefaultHostAuthentication 擴充方法使 Web API 忽略任何在主機分級配置的身份驗證。已在主機分級上啟用 cookie 預設 Web APIVisual Studio範本並用無記名權杖 Web API 級別。因為餅乾在主機分級啟用和需要 XSRF 緩解,範本還使用 SuppressDefaultHostAuthentication 來防止 Web API 管道使用基於 cookie 的校長。這種方式,Web API 將使用僅基於權杖的校長,你不需要構建 Web API 來抵禦 XSRF 攻擊的機制。

製作身份驗證和授權篩選器工作在串聯

在ASP.NETWeb API 管道中,身份驗證篩選器運行第一 — — 緊接著授權篩選器 — — 原因很簡單授權取決於建立的身份,這是身份驗證的結果。這裡是你如何可以設計要一起工作,以確保ASP.NETWeb API 的身份驗證和授權篩選器。

這種設計的基本原則給身份驗證篩選器一隻負責驗證憑據,並不能處理任何其他問題。例如,身份驗證篩選器會不接受具有 401 未經授權的狀態碼的請求,如果全權證書不存在。它只是不建立經過身份驗證的身份,和葉子如何處理匿名請求授權階段的問題。身份驗證篩選器基本上採用了三種類型的操作:

  1. 如果感興趣的憑據不是請求中,則篩選器沒有起作用。
  2. 如果憑據都存在併發現要有效,該篩選器的身份驗證的主體形式確立一個身份。
  3. 如果憑據,目前卻發現無效,該篩選器通知ASP.NETWeb API 框架通過設置一個錯誤的結果,基本上在獲取發送回要求者"未經授權"的回應結果。

如果沒有人在管道中運行的身份驗證篩選器可以檢測到不正確憑據,管道繼續運行,即使尚未建立經過身份驗證的標識。它是運行後在管道中以決定如何處理此匿名請求的元件。

在最基本的層次,授權篩選器只是檢查既定的標識是否已經過身份驗證的標識。然而,授權篩選器還可以保證:

  • 已驗證身份的使用者名是允許使用者清單中。
  • 至少一個已通過身份驗證的身份與關聯的角色是允許角色的清單。

當預置的授權篩選器執行時只有剛才所說的基於角色的存取控制時,來自開箱授權篩選器的自訂的授權篩選器可以通過檢查是身份由身份驗證篩選器的一部分的索賠執行基於聲明的存取控制。

如果授權的所有篩選器都是快樂的管道繼續執行並最終 API 控制器的操作方法生成一個請求的回應。如果身份不確定或不匹配的使用者名或角色要求,授權篩選器拒絕與 401 未經授權回應請求。圖 1 說明了兩個篩選器在三種情況中所扮演的角色:全權證書不存在,無效憑據目前的現狀與有效憑據。

安全篩選器在ASP.NETWeb API 管道
圖 1 安全篩選器在ASP.NETWeb API 管道

創建身份驗證篩選器

身份驗證篩選器是實現 IAuthenticationFilter 介面的類。此介面有兩種方法:AuthenticateAsync 和 ChallengeAsync,按以下所示:

public interface IAuthenticationFilter : IFilter
{
  Task AuthenticateAsync(HttpAuthenticationContext context, 
    CancellationToken cancellationToken);
  Task ChallengeAsync(HttpAuthenticationChallengeContext context,
    CancellationToken cancellationToken);
}

AuthenticateAsync 方法接受 HttpAuthentication­上下文作為參數。這種情況下是如何 AuthenticateAsync 方法溝通回ASP.NETWeb API 框架在身份驗證過程的結果。如果請求消息包含真實憑據,主要通過在 HttpAuthenticationCoNtext 物件的屬性設置為已通過身份驗證的主體。如果憑據無效,HttpAuthenticationCoNtext 參數的 ErrorResult 屬性設置為 UnauthorizedResult。如果請求消息不包含在所有的憑據,AuthenticateAsync 方法採取任何行動。中的代碼圖 2 顯示了一個典型實現覆蓋這三個場景的 AuthenticateAsync 方法。在此示例中使用的身份驗證的主體是 ClaimsPrincipal 只是名稱和角色的索賠。

圖 2 AuthenticateAsync 方法

public Task AuthenticateAsync(HttpAuthenticationContext context,
  CancellationToken cancellationToken)
{
  var req = context.Request;
  // Get credential from the Authorization header 
  //(if present) and authenticate
  if (req.Headers.Authorization != null &&
    "somescheme".Equals(req.Headers.Authorization.Scheme,
      StringComparison.OrdinalIgnoreCase))
  {
    var creds = req.Headers.Authorization.Parameter;
    if(creds == "opensesame") // Replace with a real check
    {
      var claims = new List<Claim>()
      {
        new Claim(ClaimTypes.Name, "badri"),
        new Claim(ClaimTypes.Role, "admin")
      };
      var id = new ClaimsIdentity(claims, "Token");
      var principal = new ClaimsPrincipal(new[] { id });
      // The request message contains valid credential
      context.Principal = principal;
    }
    else
    {
      // The request message contains invalid credential
      context.ErrorResult = new UnauthorizedResult(
        new AuthenticationHeaderValue[0], context.Request);
    }
  }
  return Task.FromResult(0);
}

使用 AuthenticateAsync 方法來執行核心身份驗證邏輯驗證的憑據在請求中,並添加身份驗證質詢的 ChallengeAsync 方法。身份驗證質詢被添加到回應時狀態碼 401 未經授權,並且要檢查的狀態碼,你需要回應物件。但 ChallengeAsync 方法不允許您檢查回應或直接設置所面臨的挑戰。事實上,此方法執行之前的操作方法,在請求處理 Web API 管道的一部分。然而,ChallengeAsync 方法的參數的 HttpAuthenticationChallengeCoNtext 允許操作結果物件 (IHttpActionResult) 將被分配到 Result 屬性。操作結果物件的 ExecuteAsync 方法等待產生回應的任務,檢查回應狀態碼,並添加 WWW 身份驗證回應標頭。中的代碼圖 3 顯示了一個典型的實現的 ChallengeAsync 方法。在此示例中,只是將添加一個硬式編碼挑戰。ResultWithChallenge 類是行動結果類創建要添加所面臨的挑戰。

圖 3 ChallengeAsync 方法

public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
  CancellationToken cancellationToken)
{
  context.Result = new ResultWithChallenge(context.Result);
  return Task.FromResult(0);
}
public class ResultWithChallenge : IHttpActionResult
{
  private readonly IHttpActionResult next;
  public ResultWithChallenge(IHttpActionResult next)
  {
    this.next = next;
  }
  public async Task<HttpResponseMessage> ExecuteAsync(
    CancellationToken cancellationToken)
  {
    var response = await next.ExecuteAsync(cancellationToken);
    if (response.StatusCode == HttpStatusCode.Unauthorized)
    {
      response.Headers.WwwAuthenticate.Add(
        new AuthenticationHeaderValue("somescheme", "somechallenge"));
    }
    return response;
  }
}

下面的代碼顯示已完成的篩選器類:

public class TokenAuthenticationAttribute : 
  Attribute, IAuthenticationFilter
{
  public bool AllowMultiple { get { return false; } }
  // The AuthenticateAsync and ChallengeAsync methods go here
}

除了實現 IAuthenticationFilter 介面,我從派生屬性所以可以作為屬性 (控制器) 類級別或方法 (操作方法) 級別應用此類。

因此,您可以創建身份驗證篩選器與單一責任的具體的憑據 (在此示例中的虛擬權杖) 進行身份驗證。身份驗證篩選器已沒有授權邏輯 ; 其唯一的目的是處理身份驗證:建立一個身份,如果有的話 (同時處理的請求消息) 並返回一個挑戰,如果任何 (同時處理回應訊息)。授權篩選器處理授權問題,如檢查是否已經過身份驗證的標識是或它是否在允許清單中的使用者或角色。

使用授權篩選器

使用授權篩選器的基本目標是要執行的授權 — — 來確定是否應允許使用者訪問請求的資源。Web API 提供的授權篩選器被稱為 AuthorizeAttribute 的實現。應用此篩選器確保身份驗證的身份。您還可以配置授權屬性與特定使用者名清單和角色允許。中的代碼圖 4 顯示使用不同屬性的身份授權各級 (全球範圍內,在控制器級別) 和行動方法級應用的授權篩選器。在此示例中的篩選器全球範圍內確保標識進行身份驗證。用於在控制器級別的篩選器確保標識進行身份驗證並與身份相關聯的至少一個角色是"管理員"。在操作方法級別使用的篩選器確保標識進行身份驗證的使用者名是"姨媽"。這裡要注意的一點是,授權篩選器在操作方法級別也將從控制器和全球各級繼承篩選器。因此,對於成功的所有篩選器的授權必須傳遞:使用者名必須是"巴德里"的角色之一必須是"管理員",使用者必須經過身份驗證。

圖 4 使用三個不同層面的授權篩選器

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other Web API configuration code goes here
    config.Filters.Add(new AuthorizeAttribute()); // Global level
  }
}
[Authorize(Roles="admin")] // Controller level
public class EmployeesController : ApiController
{
  [Authorize(Users="badri")] // Action method level
  public string Get(int id)
  {
    return “Hello World”;
  }
}

開箱 AuthorizeAttribute 是非常有用的但如果需要更多的定制,則你可以分類以執行額外的授權行為。下面的代碼演示一個自訂的授權篩選器:

public class RequireAdminClaimAttribute : AuthorizeAttribute
{
  protected override bool IsAuthorized(HttpActionContext context)
  {
    var principal =
      context.Request.GetRequestContext().Principal as ClaimsPrincipal;
    return principal.Claims.Any(c => c.Type ==
      "http://yourschema/identity/claims/admin"
      && c.Value == "true");
  }
}

此篩選器只是檢查"admin"的自訂項索賠,但您可以使用本金和任何其他附加的資訊,從 HttpActionCoNtext 來執行自訂授權在這裡。

ASP.NETWeb API 的第一個版本,在自訂授權篩選器常被誤用來實現身份驗證,但與ASP.NETWeb API 2,身份驗證篩選器現在有自己的管道中的位置,這有助於開發清潔、 模組化的代碼清楚分開的身份驗證和授權關切。

篩選器覆蓋

正如我剛才所說,授權篩選器可以應用在行動方法級別,該控制器中,水準或全球範圍內。通過全球指定授權篩選器,您可以跨所有控制器實施在所有的行動方法調用上進行授權。如果你想要幾種方法從全球範圍內配置檢查,免征,很容易做到這一點,使用 AllowAnonymous 屬性。

中的代碼圖 5 演示如何使用 AllowAnonymous 屬性在控制器級別。儘管全球範圍內應用了授權篩選,與 PublicResourcesController 一起使用的 AllowAnonymous 屬性免除從獲得授權到此控制器傳入的請求。

圖 5 使用 AllowAnonymous 屬性

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other Web API configuration code goes here
    config.Filters.Add(new AuthorizeAttribute()); // Global level
  }
}
[AllowAnonymous]
public class PublicResourcesController : ApiController
{
  public string Get(int id)
  {
    return “Hello World”;
  }
}

AllowAnonymous 提供了具體的行動可以重寫授權由更高層次的授權篩選器配置的一種方式。然而,AllowAnonymous 只允許您重寫授權。假設你想讓大多數的操作,使用 HTTP 基本驗證,而是一個行動使用公正的權杖進行身份驗證進行身份驗證。我會很高興全球配置權杖身份驗證但然後重寫這一個動作,類似于 AllowAnonymous 如何重寫授權的身份驗證。

ASP.NETWeb API 2 介紹了新的篩選器類型,來解決這種情況下,重寫的篩選器。像 AllowAnonymous,ASP.NETWeb API 2 仲介紹了重寫篩檢程式可以處理任何類型的篩選器。重寫篩檢程式,顧名思義,重寫較高的級別配置的篩選器。若要重寫配置較高的級別的身份驗證篩選器,請使用開箱屬性 OverrideAuthentication。如果你有全域應用身份驗證篩選器,並且想要阻止它運行的具體操作方法或控制器,您可以簡單地應用 OverrideAuthentication 在所需的級別。

重寫篩檢程式可用於遠遠超過僅僅停止某些篩選器的運行。說你有兩個身份驗證篩選器,一個用於身份驗證的安全權杖,另一個用於身份驗證的使用者名/密碼的 HTTP 基本方案。這兩個應用篩選器在全球範圍,使您足夠的靈活性,接受標記或使用者名/密碼的 API。下面的代碼顯示了全球範圍內應用的兩種身份驗證篩選器:

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other Web API configuration code goes here
    config.Filters.Add(new TokenAuthenticator());
    config.Filters.Add(new HttpBasicAuthenticator(realm: "Magical"));
  }
}

現在,也許你想確保只有權杖作為憑據用於訪問具體行動的方法。如何將 OverrideAuthentication 使您能夠滿足這一需要,因為它只是停止運行的所有篩選器嗎?這裡是覆蓋篩檢程式的重要特徵 — — 他們消滅所有篩選器指定較高的級別,但不刪除篩選器指定作為自己同一級別。這基本上意味著你可以添加一個或多個身份驗證篩選器為特定級別同時消除一切在較高水準。回到使用只是標記作為憑據用於訪問特定的操作方法的要求,您可以簡單地指定的 OverrideAuthentication 屬性和操作方法級的 TokenAuthenticator (這可以確保只有 TokenAuthenticator 運行操作方法 GetAllowedForTokenOnly) 下面的代碼所示:

public class EmployeesController : ApiController
{
  [OverrideAuthentication] // Removes all authentication filters
  [TokenAuthenticator] // Puts back only the token authenticator
  public string GetAllowedForTokenOnly(int id)
  {
    return “Hello World”;
  }
}

因此,覆蓋篩檢程式與ASP.NETWeb API 2 介紹了提供更多的靈活性,全球範圍內指定篩選器和運行篩選器在較低級別有選擇性地只有全球的行為在中被重寫。

OverrideAuthentication 屬性,也是開箱屬性稱為 OverrideAuthorization 中移除指定的高級別授權篩選器。與 AllowAnonymous 相比,區別在於 OverrideAuthorization 刪除上級授權篩選器。它並不會刪除指定作為本身的同一級別的授權篩選器。AllowAnony­諒解備忘錄使ASP.NETWeb API 一起跳過授權過程 — — 即使有授權篩選器指定同一級別為 AllowAnonymous,他們只是被忽略掉。

總結

您可以使用由宿主提供的選項,以及通過ASP.NETWeb API 管道提供的可擴充性點的ASP.NETWeb API 中實現身份驗證。基於主機的選項很好融入東道國管道和拒絕早些時候管道中的無效請求。ASP.NETWeb API 可擴充性點提供更細的級別的身份驗證過程的控制權。當您需要更多地控制身份驗證,例如,您想要使用不同的身份驗證機制,為不同的控制器或甚至不同的操作方法,正確的做法是通過授權篩選器實現身份驗證通過身份驗證篩選器和授權問題的關注。


Badrinarayanan Lakshmiraghavan 是與財富 500 強公司的高級顧問建築師。他是本書中,作者"ProASP.NETWeb API 安全"和"實際ASP.NETWeb API"都在 2013 年發表 Apress。 他偶爾博客在 lbadri.wordpress.com

感謝以下的微軟技術專家對本文的審閱:David馬聰
David馬聰在微軟作為軟體發展人員的工作。他是 MVC 5 和 Web API 2 產品團隊的成員。