ASP.NET MVC 不像 ASP.NET WEB FORMS 那樣提供了不少自動保護機制來保護頁面不受惡意用戶的攻擊,更明確的說,後者是致力於使應用程序免受攻擊:程序員
ASP.NET MVC 對標記和程序的運行提供了更多控制,這意味着程序員要承擔更多的責任。web
之因此應用程序存在安全隱患,主要是由於開發人員缺少足夠的信息或理解。另外,人無完人,不免有疏忽的時候,鑑於此,下面是本章的關鍵總結:數據庫
黑客、解密高手、垃圾郵件發送者、病毒、惡意軟件,它們都想進入計算機並查看或破壞裏面的數據!瀏覽器
保護應用程序的第一步,也是最簡單的一步,就是要求登陸系統的用戶訪問那些由應用程序指定的 URL。咱們能夠經過控制器上或控制器內部特定操做上的 Authorize 操做過濾器來實現。安全
Authorize 特性是 ASP.NET MVC 自帶的默認受權過濾器,可限制用戶對操做方法的訪問,若該特性運用於控制器,則會應用於控制器內部全部操做方法。服務器
有時會對用戶身份驗證和用戶受權之間的區別感到困惑,這兩個詞也比較類似!cookie
受權特性不帶任何參數,只要求用戶以某種角色身份登陸網站,換句話說,禁止匿名訪問!app
如今根據一個很是簡單的購物應用需求,建立音樂商店的應用程序。程序中的 StoreController 控制器僅包含 2 個操做,Index 和 Buy:框架
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers
{
public class StoreManagerController : Controller
{
public ActionResult Index()
{
var albums = GetAlbums();
return View(albums);
}
[Authorize]
public ActionResult Buy(int id)
{
var album = GetAlbums().Single(e => e.AlbumId == id);
return View(album);
}
private static List<Album> GetAlbums()
{
var albums = new List<Album> {
new Album {AlbumId = 1, Title = "The Fall of Math", Price = 8.99M},
new Album {AlbumId = 2, Title = "The Blue Notebooks", Price = 8.99M},
new Album {AlbumId = 3, Title = "Lost in Translation", Price = 9.99M},
new Album {AlbumId = 4, Title = "Permutation", Price = 10.99M}
};
return albums;
}
}
}
若是如今訪問 Store 控制器的 Buy 操做時,就會要求登陸。ide
下面內容很是重要,請慢讀、理解、記憶:
<location path="Admin" allowOverride="false" />
<system.web>
<authorization>
<allow roles="Administrator"/>
<deny users="?"/>
</authorization>
</system.web>
這種方式在 MVC 框架中沒法正常工做,緣由有兩個。首先,請求再也不映射到屋裏目錄;其次,可能存在多種查找同一控制器的方式。
實現安全性的最好方法是,安全性檢查儘量的接近要保護的對象。可能有高於堆棧的檢查,但最終都要確保實際資源的安全。這樣不管用戶如何得到資源,該方式都會對其進行安全性檢查。因而,也就沒必要依賴路由和 URL 受權來確保控制器安全了。
Authorize 特性就起這個做用:
上面例子在後臺是如何操做的呢?原來,在 ASP.NET MVC 的 InternetApplication 模板包含一個基本的 AccountController,它支持 ASP.NET Membership 和 OAuth 驗證的帳戶管理。
Authorize 特性是一個過濾器,它能先於控制器操做執行。首先會執行它在 OnAuthorization 方法中的主要操做,這是一個在接口 IauthorizationFilter 中定義的標準方法,查看源碼就會發現,基本的安全機制正在覈實 ASP.NET 上下文中存儲的基自己份驗證信息:
return HttpContext.User.Identity.IsAuthenticated;
若是用戶驗證失敗,就會返回一個 HttpUnauthorizedResult 操做結果,產生一個 HTTP 401(未受權)的狀態碼。這個狀態碼被 FormsAuthenticationModule 的 Onleave 方法截獲,並轉而重定向到配置中的登陸頁面。
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
MVC 框架 InternetApplication 模板提供的這種方式,在簡單的應用場合中能夠輕鬆添加受權,而不須要編寫任何額外代碼及配置。
有時可能會但願受權級別是控制器,而不是在內部每個操做上添加 Authorize 特性。此時,能夠添加 Authorize 特性至 Controller 上。
大部分網站,基本上整個應用程序都是須要受權的。這種情形下,默認受權要求和匿名訪問少數網頁就變得極其簡單。把 AuthorizeAttribute 配置爲全局過濾器,而使用 AllowAnonymous 特性標註容許匿名訪問的控制器或方法。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
}
這樣就限制了對整個應用程序全部操做的訪問,但也別忘了標註容許匿名訪問的控制器或操做(若是有的話)。
[Authorize(Roles = "Administrator")]
public class StoreManagerController : Controller
這樣就限定了受權訪問的用戶角色只能是管理員角色。顧名思義(Roles 是複數),傳遞的角色列表能夠是逗號間隔的字符串;也能夠受權給一組用戶 Users = "xx,xxx";也能夠二者同時使用。
固然,應當使用角色而非用戶組。另外,當建立角色組時,可考慮使用基於特權的角色分組,像 CanEditAlbums 這樣的角色組遠比 SuperAdmin、CEOOffice更爲精細,更爲便於管理。
ASP.NET MVC 的好處之一就是它運行在成熟且功能齊全的 ASP.NET 核心之上。而 ASP.NET MVC 中的身份驗證和受權創建在 System.Web.Security 命名空間中的 Role 類和 Membership 類之上。這樣作是有好處的:
運用本地數據庫維護用戶信息也有一些嚴重的負面影響:
OAuth 和 OpenID 是開放的受權標準。這些協議容許用戶使用他們已有的帳戶登陸咱們的網站,這些帳戶來自於他們信任的網站(提供器)。過去,配置網站以支持 OAuth 和 OpenID 是很是難以實現的。緣由有如下兩點:首先是協議複雜,而後是頂級提供器對這兩種協議的實現方式不同。
MVC 4 經過在 Internet 模板中內置支持 OAuth 和 OpenID 極大化的簡化了這一點。這種支持包括了一個更新的 AccountController、便於註冊和帳戶管理的視圖以及構建在流行庫 DotNetOpenAuth 之上的工具類!
新的登陸頁面會出現兩個登陸的選項,以下圖:
須要顯式的啓用外部網站,以便利用它們的帳戶登陸咱們的網站。可喜的是,這個操做很是簡單,能夠在 AuthConfig.cs 中配置受權提供程序。默認文件中的全部驗證提供器都會註釋掉,以下:
public static void RegisterAuth()
{
// 若要容許此站點的用戶使用他們在其餘站點(例如 Microsoft、Facebook 和 Twitter)上擁有的賬戶登陸,
// 必須更新此站點。有關詳細信息,請訪問 http://go.microsoft.com/fwlink/?LinkID=252166
//OAuthWebSecurity.RegisterMicrosoftClient(
// clientId: "",
// clientSecret: "");
//OAuthWebSecurity.RegisterTwitterClient(
// consumerKey: "",
// consumerSecret: "");
//OAuthWebSecurity.RegisterFacebookClient(
// appId: "",
// appSecret: "");
//OAuthWebSecurity.RegisterGoogleClient();
}
使用OAuth提供器的網站(如Facebook、Twitter等)要求咱們把網站註冊爲一個應用程序,這樣它們就會提供咱們一個客戶端 id 和一個口令,咱們利用 OAuth 提供器就能夠進行驗證。利用 OpenID(如 Google 和 Yahoo)的網站不須要註冊應用程序,咱們也不須要客戶端 id 和口令。
因爲不用註冊,不用填寫參數,所以配置 OpenID 提供器是很是簡單的,Google、Yahoo 等都有現成的實現,而 myOpenID 須要建立註冊一個自定義的客戶端(經過 using 語句引入一些必要的命名空間,位於 DotNetOpenAuth 下):
using Microsoft.Web.WebPages.OAuth;
using DotNetOpenAuth.AspNet.Clients;
using DotNetOpenAuth.OpenId.RelyingParty;
namespace OAuthMVC
{
public static class AuthConfig
{
public static void RegisterAuth()
{
// 配置 Google 提供器
OAuthWebSecurity.RegisterGoogleClient();
// 配置 Yahoo 提供器
OAuthWebSecurity.RegisterYahooClient();
// 配置 myOpenID 提供器,先建立 OpenIdClient,再進行註冊
var MyOpenIdClient = new OpenIdClient("myopenid", WellKnownProviders.MyOpenId);
OAuthWebSecurity.RegisterClient(MyOpenIdClient, "MyOpenID", null);
}
}
}
運行程序,測試登陸的效果,如圖:
Google 被和諧,點擊 Yahoo 能夠導航到登陸界面:
輸入帳戶密碼以後,Yahoo 詢問是否贊成登陸咱們的網站,選擇 Agree:
驗證成功,並受權後,瀏覽器返回咱們的站點,此時能夠完成一些咱們站點的註冊步驟,並在單擊註冊後,會被做爲一個已認定的用戶重定向到主頁:
註冊成功:
點擊用戶名能夠管理本身的帳戶,添加一個本地帳戶和密碼或者綁定額外的外部登陸提供器:
須要在第三方網站將本身的站點註冊爲一個 App,以後使用得到的 AppID 和密鑰就能夠註冊了,例以下面的 Facebook 站點:
public static void RegisterAuth()
{
OAuthWebSecurity.RegisterFacebookClient(appId: "123456789", appSecret: "abcdefg");
}
儘管 OAuth 和 OpenID 簡化了安全性編碼,但也給應用程序引入了其餘潛在的攻擊媒介,若是一個提供器網站被破壞,或者網站之間的安全通訊遭到破壞,攻擊者可能會破壞咱們的網站登陸、或者捕獲用戶信息。所以要作到如下幾點:
1. 可信的外部登陸提供器,使用知名的提供器,只支持咱們信任的站點
2. 要求 SSL 登陸,外部提供器到網站的回調中包含擁有用戶信息的安全令牌,當令牌在互聯網傳遞時,使用 HTTPS 傳輸是很重要的,這樣能夠防止信息被攔截。
[RequireHttps]
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}