private byte[] GetRandomBytes(int iByte)
        
{
            RNGCryptoServiceProvider rng 
= new RNGCryptoServiceProvider();
            
byte[] randomData = new byte[iByte];
            rng.GetBytes(randomData);
            
return randomData;
        }

        
private string BytesToHex(byte[] byteArr)
        
{
            StringBuilder sb 
= new StringBuilder(64);
            
for(int i=0;i<byteArr.Length;i++)
                sb.AppendFormat(
"{0:X2}",byteArr[i]);
            
return sb.ToString();

        }
身份验证
• 身份验证是指以下过程:获取标识凭据(如
用户名和密码),并对照某一颁发机构来验
证这些凭据。
• ASP.NET 提供了四个身份验证提供程序:
– 表单身份验证
– Windows 身份验证
– Passport 身份验证
– 默认身份验证

表单身份验证
表单身份验证是指以下系统:将未经身
份验证的请求重定向到一个超文本标记语
言(HTML) 表单,使用户能够在其中键入他
们的凭据。在用户提供凭据并提交该表单
后,应用程序对请求进行身份验证,然后
系统以Cookie 的形式发出身份验证票证。
此Cookie 包含凭据或用于重新获取标识的
密钥。浏览器的后续请求自动包含此
Cookie。

Windows 身份验证
在Windows 身份验证中,IIS 执行身份
验证,并将经过身份验证的标记传递给
ASP.NET 工作进程。使用Windows 身份
验证的优点是它需要的编码最少。在将请
求传递给ASP.NET 之前,您可能需要使用
Windows 身份验证来模拟IIS 进行验证的
Windows 用户帐户。

Passport 身份验证
Passport 身份验证是Microsoft 提供的
集中式身份验证服务,它为成员站点提供
单一登录和核心配置文件服务。通常,当
您需要跨越多个域的单一登录功能时,将
使用Passport 身份验证。

默认身份验证
当Web 应用程序不需要任何安全功能
时,将使用默认身份验证;此安全提供程
序需要匿名访问。在所有的身份验证提供
程序中,默认身份验证为应用程序提供了
最高的性能。当您使用自己的自定义安全
模块时,也可以使用此身份验证提供程序。
private void btnLoginBetter_Click(object sender, System.EventArgs e)
        
{
            SqlConnection con 
= new SqlConnection();
            con.ConnectionString 
= System.Configuration.ConfigurationSettings.AppSettings["DSN"];
            con.Open();
        
            
string strSql = "select UserName,UserPass from tbUserInfo where UserName=@username and UserPass=@userpass";
            SqlParameter sqlpUser 
= new SqlParameter("@username",SqlDbType.NVarChar,30);
            sqlpUser.Value 
= tbName.Text;
            SqlParameter sqlpPass 
= new SqlParameter("@userpass",SqlDbType.NVarChar,30);
            sqlpPass.Value 
= tbPass.Text;
            SqlCommand com 
= new SqlCommand(strSql,con);
            com.Parameters.Add(sqlpUser);
            com.Parameters.Add(sqlpPass);
            SqlDataReader dr 
= com.ExecuteReader();
            
//以下执行查询
            bool bExist = false;
            
while(dr.Read())
            
{
                bExist 
= true;
            
            }

            lbDiag.Text 
= strSql;
            
if(bExist)
                lbMsg.Text 
= "您好!"+Server.HtmlEncode(tbName.Text);
            
else
                lbMsg.Text 
= Server.HtmlEncode(tbName.Text) + "不能进入!";
            con.Close();
        }
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.Web.Security;
using System.Security.Cryptography;
using System.Text;
using System.IO;
namespace CommandExample
{
    
/// <summary>
    
/// login 的摘要说明。
    
/// </summary>

    public class Login01 : System.Web.UI.Page
    
{
        
protected System.Web.UI.WebControls.Label Label1;
        
protected System.Web.UI.WebControls.TextBox tbName;
        
protected System.Web.UI.WebControls.TextBox tbPass;
        
protected System.Web.UI.WebControls.Button btnLoginBetter;
        
protected System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
        
protected System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator2;
        
protected System.Web.UI.WebControls.CheckBox PersistCookie;
        
protected System.Web.UI.WebControls.Label Label2;
    
        
private void Page_Load(object sender, System.EventArgs e)
        
{
            
// 在此处放置用户代码以初始化页面
        }


        
Web Form Designer generated code

        
private void btnLoginBetter_Click(object sender, System.EventArgs e)
        
{
            
bool bExist = AuthenticateUser(tbName.Text,tbPass.Text);
            
if(bExist)
            
{
                
//1) //创建一个验证票据
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, tbName.Text,DateTime.Now,
                    DateTime.Now.AddMinutes(
30),PersistCookie.Checked,"User");
                
//2) //并且加密票据
                string cookieStr =  FormsAuthentication.Encrypt(ticket);
                
//3) 创建cookie
                HttpCookie cookie =new HttpCookie(FormsAuthentication.FormsCookieName,cookieStr);
                
if(PersistCookie.Checked) //如果用户选择了保存密码
                    cookie.Expires=ticket.Expiration;//设置cookie有效期
                
//cookie存放路径
                cookie.Path = FormsAuthentication.FormsCookiePath;
                Response.Cookies.Add(cookie);
                
// 4) do a redirect
                string strRedirect;
                strRedirect
=Request["ReturnUrl"];
                
if(strRedirect==null)
                    strRedirect
="default.aspx";
                Response.Redirect(strRedirect,
true);
            }

            
else
                Response.Write(
"<script language='javascript'>alert('用户名称或密码错误!')</script>");
            
        }

        
private bool ArraysEqual(byte[] array1,byte[] array2)
        
{
            
bool bResult = true;
            
if(array1==null)
                
throw new ArgumentNullException("array1");
            
if(array2==null)
                
throw new ArgumentNullException("array2");
            
if(array1.Length == array2.Length)
            
{
                
for(int i=0;i<array1.Length;i++)
                
{
                    
if(array1[i]!=array2[i])
                    
{
                        bResult 
= false;
                        
break;
                    }

                }

            }


            
return bResult;
        }

        
private bool AuthenticateUser(string strUserName, string strUserPass)
        
{
            SqlConnection con 
= new SqlConnection();
            con.ConnectionString 
= System.Configuration.ConfigurationSettings.AppSettings["DSN"];
            con.Open();
        
            
string strSql = "sp_getuserdetails";
            SqlCommand com 
= new SqlCommand(strSql,con);
            com.CommandType 
= CommandType.StoredProcedure;
            SqlParameter sqlpUser 
= new SqlParameter("@acctname",SqlDbType.NVarChar,64);
            sqlpUser.Value 
= tbName.Text;
            SqlParameter sqlpPasshash 
= new SqlParameter("@passhash",SqlDbType.NVarChar,50);
            sqlpPasshash.Direction 
= ParameterDirection.Output;
            SqlParameter sqlpPasssalt 
= new SqlParameter("@passsalt",SqlDbType.NVarChar,50);
            sqlpPasssalt.Direction 
= ParameterDirection.Output;
            com.Parameters.Add(sqlpUser);
            com.Parameters.Add(sqlpPasssalt);
            com.Parameters.Add(sqlpPasshash);
            com.ExecuteNonQuery();

            
string hash = com.Parameters["@passhash"].Value.ToString();
            
string salt = com.Parameters["@passsalt"].Value.ToString();

            
bool bExist = false;
            
if(hash==null||salt==null)
                bExist 
= false;
            
else
            
{
                
byte[] saltBits = Convert.FromBase64String(salt);
                
byte[] hashBits = Convert.FromBase64String(hash);
                
byte[] passBits = Encoding.Unicode.GetBytes(strUserPass);
                
                HashAlgorithm hashAlg 
= SHA1.Create();
                CryptoStream cs 
= new CryptoStream(Stream.Null,hashAlg,CryptoStreamMode.Write);
                cs.Write(passBits,
0,passBits.Length);
                cs.Write(saltBits,
0,saltBits.Length);
                cs.FlushFinalBlock();
                cs.Close();

                
byte[] digest = hashAlg.Hash;
                
if (ArraysEqual(digest,hashBits))
                    bExist 
= true;
                
else
                    bExist 
= false;
            }

            con.Close();
            
return bExist;
        }


    }

}

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Web.Security;
using System.Security.Principal;
using System.Runtime.InteropServices;
namespace Security
{
    
/// <summary>
    
/// ASPNETImp 的摘要说明。
    
/// </summary>

    public class ASPNETImp : System.Web.UI.Page
    
{
        
protected System.Web.UI.WebControls.Label lbExist;
        
protected System.Web.UI.WebControls.Label Label2;
        
public const int LOGON32_LOGON_INTERACTIVE = 2;
        
public const int LOGON32_PROVIDER_DEFAULT = 0;
        WindowsImpersonationContext impersonationContext; 
        [DllImport(
"advapi32.dll", CharSet=CharSet.Auto)]
        
public static extern int LogonUser(String lpszUserName,String lpszDomain,
            String lpszPassword,
int dwLogonType,int dwLogonProvider,
            
ref IntPtr phToken);
        [DllImport(
"advapi32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto, 
             SetLastError
=true)]
        
public extern static int DuplicateToken(IntPtr hToken,int impersonationLevel, ref IntPtr hNewToken);
        
private void Page_Load(object sender, System.EventArgs e)
        
{
            
//noImpersonate();
            
//ImpersonateIIS();
            ImpersonateUser();
    
        }

        
private void noImpersonate()
        
{
            
try
            
{
                
if(File.Exists("c:\\Documents and Settings\\shaozhidong\\test.txt"))
                    lbExist.Text 
= "存在!";
                
else
                    lbExist.Text 
= "该文件不存在!";
            }

            
catch(Exception)
            
{
                lbExist.Text 
= "没有权限!";
            }

        }

        
private void ImpersonateIIS()
        
{
            
// 在代码中模拟IIS认证帐号
            System.Security.Principal.WindowsImpersonationContext impersonationContext;
            impersonationContext 
= ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();

            
if(File.Exists("c:\\Documents and Settings\\shaozhidong\\test.txt"))
                lbExist.Text 
= "存在!";
            
else
                lbExist.Text 
= "该文件不存在!";
            
            impersonationContext.Undo();
        }

        
private void ImpersonateUser()
        
{
            
//在代码中模拟指定账号
            if(impersonateValidUser("shaozhidong""shaozhd""111"))
            
{   
                
if(File.Exists("c:\\Documents and Settings\\shaozhidong\\test.txt"))
                    lbExist.Text 
= "存在!";
                
else
                    lbExist.Text 
= "该文件不存在!";
                undoImpersonation();   
            }
 
            
else
            
{    
                lbExist.Text 
= "权限不够!";
            }

        }

        
private bool impersonateValidUser(string userName, string domain, string password)
        
{   
            WindowsIdentity tempWindowsIdentity;   
            IntPtr token 
= IntPtr.Zero;   
            IntPtr tokenDuplicate 
= IntPtr.Zero;
            
if(LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, 
                LOGON32_PROVIDER_DEFAULT, 
ref token) != 0)  
            
{      
                
if(DuplicateToken(token, 2ref tokenDuplicate) != 0
                
{         
                    tempWindowsIdentity 
= new WindowsIdentity(tokenDuplicate); 
                    impersonationContext 
= tempWindowsIdentity.Impersonate(); 
                    
if (impersonationContext != null
                        
return true
                    
else 
                        
return false;  
                }
   
                
else 
                    
return false;  
            }
    
            
else 
                
return false;
        }

        
private void undoImpersonation()
        
{     
            impersonationContext.Undo();
        }
 
        
Web Form Designer generated code
    }

}

表单身份验证的开发步骤
• 1. 将IIS 配置为使用匿名访问。
2. 将ASP.NET 配置为使用表单身份验证。
3. 创建登录Web 表单并验证提供的凭据。
4. 从自定义数据存储中检索角色列表。
5. 创建表单身份验证票(在票中存储角色)。
6. 创建一个IPrincipal 对象。
7. 将IPrincipal 对象放到当前的HTTP 上下文
中。
8. 基于用户名/角色成员身份对用户进行授权。

授权
• 授权是指验证经身份验证的用户是否可以访问
请求资源的过程。
• ASP.NET 提供以下授权提供程序:
– FileAuthorization:FileAuthorizationModule 类
进行文件授权,而且在使用Windows 身份验证时
处于活动状态。
– UrlAuthorization:UrlAuthorizationModule 类进
行统一资源定位器(URL) 授权,它基于URI 命名
空间来控制授权。URI 命名空间可能与NTFS 权
限使用的物理文件夹和文件路径存在很大的差异。

授权
• 若要建立访问特定目录的条件,则必须将
一个包含<authorization> 部分的配置文
件放置在该目录中。为该目录设置的条件
也会应用到其子目录,除非子目录中的配
置文件重写这些条件。此部分的常规语法
如下所示。
• <[element] [users] [roles] [verbs]/> 元素是
必需的。必须包含users 或roles 属性。可
以同时包含二者,但这不是必需的。

• 以下示例向Kim 和管理角色的成员授予权限,而
拒绝John 和所有匿名用户:
• <authorization>
• <allow users="Kim"/>
• <allow roles="Admins"/>
• <deny users="John"/>
• <deny users="?"/>
• </authorization>

• 若要允许John 并拒绝其他任何人,可以构
造下面的配置部分。
– <authorization> <allow users="John"/> <deny
users="*"/> </authorization>
• 下面的示例允许每个人使用GET,但只有
Kim 可以使用POST。
– <authorization>
– <allow verb="GET" users="*"/>
– <allow verb="POST" users="Kim"/>
– <deny verb="POST" users="*"/>
– </authorization>
ASP.NET模拟
缺省情况下,ASP.NET应用程序以本机
的ASPNET帐号运行,该帐号属于普通用
户组,权限受到一定的限制,以保障
ASP.NET应用程序运行的安全。但是有时
需要某个ASP.NET应用程序或者程序中的
某段代码执行需要特定权限的操作,比如
某个文件的存取,这时就需要给该程序或
相应的某段代码赋予某个帐号的权限以执
行该操作,这种方法称之为身份模拟
(Impersonation)。

启用模拟的方法
• 在ASP.NET应用程序中使用身份模拟一般用于资源
访问控制,主要有如下几种方法:
– 模拟IIS认证帐号:
<IDENTITY impersonate="true" />
– 在某个ASP.NET应用程序中模拟指定的用户帐号
<IDENTITY impersonate="true"
userName="accountname" password="password" />
– 在代码中模拟IIS认证帐号
– 在代码中模拟指定的用户帐号

启用模拟的方法
• 在代码中使用身份模拟更加灵活,可以在
指定的代码段中使用身份模拟,在该代码
段之外恢复使用ASPNET本机帐号。该方
法要求必须使用Windows的认证身份标识。
ASP.NET进程标识
• 使用权限最小的账户
– 使用权限最少的帐户可以减少与进程攻击相关的威胁。
• 避免作为SYSTEM运行
• 域控制器和ASP.NET 进程帐
– 一般情况下,不建议在域控制器上运行Web 服务器,
因为对服务器的攻击就是对域的攻击。
• 使用默认ASPNET 帐户
– 已将本地ASPNET 帐户明确配置为使用尽可能最少的
权限集运行ASP.NET Web 应用程序。如果可能,尽
量使用ASPNET。

存储机密
• Web 应用程序通常需要存储机密。需要妥
善保管这些机密,以防止不道德的管理员
和有恶意的Web 用户进行访问
• 机密的典型示例包括:
– SQL 连接字符串。一个常见的错误是以纯文本
形式存储用户名和密码。
– Web.config 中的固定标识。
– Machine.config 中的进程标识。
– 用于安全地存储数据的密钥。
– 用于根据数据库进行表单身份验证的密码。
在ASP.NET 中存储机密的选项
NET Web 应用程序开发人员可以使用多种方法来存储机密。
它们包括:
• .NET 加密类。.NET 框架包含可用于加密和解密的类。这
些方法要求安全地存储加密密钥。
• 数据保护API (DPAPI)。DPAPI 是一对Win32 API,它使
用从用户密码派生的密钥对数据进行加密和解密。在使用
DPAPI 时,您并不需要进行密钥管理。操作系统对作为
用户密码的密钥进行管理。
• COM+ 构造函数字符串。如果应用程序使用服务组件,则
可以在对象构造字符串中存储机密。该字符串以明文形式
存储在COM+ 目录中。
• CAPICOM。这是一个Microsoft COM 对象,它提供对基
础加密API 基于COM 的访问。
• 加密API。这些API 是执行加密和解密的低级Win32 API。
使用加密
• 使用名称空间
System.Security.Cryptography:该命名空
间提供加密服务,包括安全的数据编码和解
码,以及许多其他操作,例如散列法、随机
数字生成和消息身份验证。
• 使用RNGCryptoServiceProvider,代替
System.Random.
使用最佳实践
• 如果应用程序使用表单身份验证,而且在用户身份验
证中需要考虑性能问题,则检索角色列表并将其存储
在身份验证票中。
• 如果使用表单身份验证,则始终给每个请求创建一个
主体并将其存储在上下文中。
• 如果角色太多而无法存储在身份验证Cookie 中,则
使用全局应用程序缓存来存储角色。
• 不要创建权限最少的自定义帐户来运行ASP.NET。
而是应更改ASPNET 帐户密码,并在应用程序需要
访问的任何远程Windows 服务器上创建重复帐户。
• 如果必须创建自定义帐户以运行ASP.NET,请使用
权限最少的用户。例如:
• 如果主要考虑管理问题,请使用权限最少的域帐户。
使用最佳实践
• 如果使用本地帐户,则必须在Web 应用程序需要
访问的任何远程计算机上创建重复帐户;如果应
用程序需要访问非信任域中的资源或者防火墙禁
止Windows 身份验证,则必须使用本地帐户。
• 不要使用本地SYSTEM 帐户来运行ASP.NET。
• 不要给ASPNET 帐户授予“充当操作系统的一部
分”权限。
• 在以下情况中使用SSL:
– 在浏览器和Web 服务器之间传送安全敏感信息时。
– 使用基本身份验证(以保护凭据)时。
– 使用表单身份验证进行身份验证(与个性化相对)时。
• 避免使用纯文本形式存储机密。

posted on 2006-05-30 16:06  公木子  阅读(668)  评论(0编辑  收藏  举报