摘要
安全性是 ASP.NET Web 应用程序中一个非常重要的方面,它涉及内容非常广泛,不能在一篇文章内说明所有的安全规范,本文讲述如何利用IIS以及Forms 身份验证构建安全的 ASP.NET 应用程序,它是目前被使用最多最广的验证/授权方式.
本文分别以ASP.NET1.1与ASP.NET2.0在Forms 身份验证上的实现方法,以及ASP.NET2.0较上一版本有哪些改进或变化进行说明.相信读者都己经看过许多类似这样的文章,不伦是在网上或是某些专业书籍上,最近又有模式&实践小组成员发布WCF安全模型指南,可见构建网站安全总是不过时的话题,作者认为此文也绝对是您应该收藏的参考资料.
ASP.NET 安全性的工作原理
网站在安全性方面有一个常见的要求:特定的页面仅允许某些成员或其他经过身份验证的用户浏览.充分利用Forms身份验证是最好的方式.
身份验证
从实现机制来说ASP.NET1.1与ASP.NET2.0的安全模型是一致的.首先配置网站为Forms 身份验证模式,之后用户访问网站的URL,Forms 身份验证系统会将未经身份验证的请求重定向到指定的登录页.用户输入凭据(用户名密码)并提交该页.如果验证程序验证用户的身份合法,则系统会向客户端发出一个特定 Cookie(.NET1.1不支持无Cookie模式),它代表用户的身份验证票据.这样后续的请求中,客户端浏览器会把该Cookie一同发送致服务器,如果该Cookie有效则用户通过身份验证并允许对原始请求的资源的访问.
授权
如果用户的请求被验证通过了,但是他请求的URL是否允许用户访问了呢,这就用到了授权.可以通过应用程序配置文件来进行授友也可以在程序中使用代码来验证用户是否有资格访问该资源.如果授权失败,则 ASP.NET 将用户重定向到登录页.如果用户已被授权,则将允许用户访问受保护资源.
ASP.NET1.1实现方式
ASP.NET1.1的实现方式非常简单,不过我们还是需要手写一些代码的,下面我们就一步一步地实现.应用程序配置节的详细说明请参考MSDN相关文档.
l 配置应用程序使用 Forms 身份验证,编辑web.config文件
<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".ASPXCOOKIEAUTH" loginUrl="Login.aspx" protection="All" timeout="30" path="/" />
</authentication>
<authorization>
<deny users="?" /> <!—拒绝匿名 -->
</authorization>
......
</system.web>
<location path="Admin"><!—配置授权,只允许拥有Admins角色的用户访问这个目录下的文件(*.aspx)-->
<system.web>
<authorization>
<allow roles="Admins"/><!—虽然下面配置为拒绝所有用户,但是allow的优先级比deny高.-->
<deny users="*" /><!—拒绝所有用户 -->
<!—
一个用户或角色必须特别指定为拒绝,才能拒绝该用户或角色对URL的权限.如果上面的示例没有指定<deny users="*" />元素,则将允许所有通过身份验证的用户访问所请求的 URL,而不考虑其所属的角色.
-->
</authorization>
</system.web>
</location>
</configuration>
l 创建登录页面Login.aspx
创建用户身份主体
ASP.NET1.1安全模型提供了四种授权方法,这四种方法都使用HttpContext.User对象进行验证授权.
l 使用应用程序配置进行授权,只有具有指定角色的用户才能访问web.config所在的文件夹与子文件夹
<authorization>
<allow roles="Admins"/>
<deny users="?"/>
</authorization>
l 使用PrinciplePermissionAttribute控制对类和方法的访问,只允许角色为Admins的成员才能调用该方法
[System.Security.Permissions.PrincipalPermission(System.Security.Permissions.SecurityAction.Demand,Role=” Admins”)]
public static bool MethodName()
{
...
}
l 以编程方式使用PrinciplePermission类控制对代码块的访问,只允许角色为Admins的成员调用Demand之后的代码
public static bool MethodName()
{
System.Security.Permissions.PrincipalPermission perm = new System.Security.Permissions.PrincipalPermission(null, "Admins");
perm.Demand();
...
}
l 使用Iprincipal.IsInRole方法,只允许角色为Admins的成员运行if中的代码,大部分情况我们都使用这种方法判断用户是否有权限.
public static bool MethodName()
{
if (HttpContext.Current.User.IsInRole("Admins"))
{
//some code
}
}
针对以上的特点,程序员必须在合适的地方创建HttpContext.User对象,以达到验证模型的要求.开发人员必须编写HttpApplication:: AuthenticateRequest事件.该事件的发生代表着用户己经通过Forms身份验证.
在Global.asax中实现Application_AuthenticateRequest.
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
string encryptedTicket = cookie.Value;
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encryptedTicket);
//获取在登录验证时加入验证票据的用户所拥有的角色,但真正开发时请不这样做,建议从数据库中获取该用户角色信息.
//因为Cookie本身有长度的限制,并且将用户角色存储到客户端也不是安全的行为.
//大家想想如果Cookie不限制大小,那么它的尺寸大到几MB或GB时