3.3 Intranet系统的选择决策流程 参见图2。
3.4 SQL Server用户验证 对SQL Server的客户端进行验证,一般说来Windows身份验证要比SQL Server身份验证更安全,原因主要有以下几点: 前者负责管理用户的凭据信息,而且用户的凭据不会在网络上传输。可以避免在连接字符串中嵌入用户名和密码。可通过密码过期时限、最小密码长度、以及多次无效登录后请求的帐户锁定等措施改进登录安全性。这样可以见少词典攻击的威胁。 但是某些特定的应用程序方案中不允许使用Windows身份验证,例如: 数据库客户端和数据库服务器由一个防火墙分隔开,从而导致无法使用Windows身份验证。应用程序需要使用多个标识连接到一个或多个数据库。连接到的数据库不是SQL Server。在ASP.NET中没有一种安全的方式以特定的Windows用户的身份运行代码。 在以上这些方案中,将必须使用SQL身份验证,或是数据库的本机身份验证机制。
4. ASP.NET身份验证实现 4.1 方案特性在这部分,仅提供了一种Intranet下交互式WEB应用程序的身份验证的实现,本方案假设具有以下特性: 只有通过了身份验证的客户端才能访问应用程序。数据库相信应用程序对用户进行了相应的身份验证-即应用程序代表用户对数据库进行调用。 WEB应用程序通过使用ASP.NET进程帐户连接到数据库。用户的凭据信息是根据SQL Server数据库进行验证的。使用窗体身份验证模式。 在WEB应用程序中,用户的凭据信息是根据SQL Server数据库,采用窗体身份验证模式,便于实现用户个性化设计。采用应用程序代表用户对数据库进行调用的方式,可采用受信任子系统模型,更好地利用数据库连接池,并且可以保证用户不能直接访问后端数据库,另外可以减少后端的ACL管理工作。
4.2 安全配置步骤 4.2.1 IIS配置步骤 对Web服务的虚拟根目录启用匿名访问。
主要方法是使用IIS MMC管理单元,右击应用程序的虚拟目录,然后单击属性---〉目录安全性--〉匿名访问和安全控制--〉编辑。
4.2.2 ASP.NET配置步骤 1. 将ASPNET帐户(用于运行ASP.NET)的密码重新设置为一个更安全的密码。
这样允许在数据库服务器上复制一个本地帐户(具有相同的用户名和密码)。为了使用Windows身份验证连接到数据库时,能够使ASPNET帐户对来自数据库的网络身份验证要求进行响应,这是必须的。
具体方法是编辑位于%windr%\Microsoft.NET\Framework\v1.1.4322\CONFIG目录下的 Machine.config文件,将<processModel>元素上的密码属性重新配置,将其默认值<!-UserName= "machine" password="AutoGenerate" -->改为<!-UserName="machine" password="NewPassword" -->。
2. 配置ASP.NET,使用窗体身份验证。
编辑位于WEB服务的虚拟根目录下的Web.config文件,将<authentication>元素设置为:
<authentication mode="Forms" >
<forms name="MyAppFormAuth" loginUrl="login.aspx" protection="All" timeout="20" path="/">
</forms>
</authentication>
4.2.3 配置SQL Server 1. 在SQL Server数据库上创建一个和ASP.NET进程帐户匹配的Windows帐户。
用户名和密码必须和ASP.NET应用程序帐号匹配。
2. 配置SQL Server,使其使用Windows身份验证。
3. 为自定义的ASP.NET应用程序帐户创建一个SQL Server登录,授予对SQL Server的访问权。
4. 创建一个新的数据库用户,并将登录名映射为数据库用户。
5. 创建一个用户定义的新数据库角色,并将数据库用户添加到该角色。
6. 为数据库角色确定数据库权限。
4.3 程序代码 4.3.1 身份验证事件序列 当未通过身份验证的用户试图放一个受保护的文件或资源被拒绝时,触发的事件序列如图3所示。
4.3.2 代码实现步骤 1. 建一个WEB登录窗体并验证用户提供的凭据信息
根据SQL Server数据库来验证凭据信息。
2. 从数据库里获取角色列表
3. 创建窗体身份验证票证
在票证中保存所获取的角色信息。示例代码如下:
private void btnLogin_Click(object sender, System.EventArgs e)
{
//根据SQL Server数据库进行验证(具体实现略)。
bool isAuthenticated = IsAuthenticated( txtUserName.Text, txtPassword.Text );
if (isAuthenticated == true )
{
//获取用户的角色
string roles = GetRoles( txtUserName.Text, txtPassword.Text ); // 创建身份验证票证
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, // version
txtUserName.Text, // user name
DateTime.Now, // creation
DateTime.Now.AddMinutes(60),// Expiration
false, // Persistent
roles ); // User data
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
// 创建Cookie
HttpCookie authCookie =
new HttpCookie(FormsAuthentication.FormsCookieName,
encryptedTicket);
Response.Cookies.Add(authCookie);
// 将用户重定向到最初请求页面。
Response.Redirect( FormsAuthentication.GetRedirectUrl(
txtUserName.Text,
false ));
}
}
4. 创建IPrincipal对象 可在Application_AuthenticateRequest事件中创建一个IPrincipal对象,一般使用GenericPrincipal类。
5. 将IPrincipal对象置于当前的HTTP上下文
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// 提去窗体身份验证cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if(null == authCookie)
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch(Exception ex)
{
return;
}
if (null == authTicket)
{
return;
}
//提取角色
string[] roles = authTicket.UserData.Split(new char[]{'|'});
// 创建Identity object
FormsIdentity id = new FormsIdentity( authTicket );
GenericPrincipal principal = new GenericPrincipal(id, roles);
Context.User = principal;
}
具体的代码读者可以自行补充完成。
5. 后记与授权与安全通讯有关的内容将另外论述。 ---------------------- 服务器安全讨论区
http://www.safe263.cn