摘要
ASP.NET Forms 身份驗證允許用戶將憑據(用戶名和密碼)輸入到 Web Form 來標識其身份。在收到這些憑據時,Web 應用程序可以根據數據源來檢查這些憑據,從而對用戶進行身份驗證。
本模塊描述如何使用密碼哈希安全地將用戶憑據存儲在 SQL Server 中,以及如何根據包含在 SQL Server 中的帳戶數據庫對用戶進行身份驗證。
預備知識
安全地存儲用戶憑據包含兩個關鍵概念:
• 存儲密碼摘要。出於安全性考慮,請不要將密碼明文存儲在數據庫中。本模塊描述如何創建和存儲用戶密碼的單向哈希而非密碼本身。如果要存儲加密的用戶密碼,建議選擇這種方法,因為它避免了與加密技術相關的密鑰管理問題。
為增加安全性並減輕與字典攻擊相關的威脅,本模塊中描述的方法在創建密碼哈希前,將 salt(以加密方式生成的隨機數)與密碼結合起來。
• 重要事項 不將密碼存儲在數據庫中的一個缺點是,一旦用戶忘記密碼,則無法恢復。因而,應用程序應使用密碼提示,並將它們與密碼摘要一起存儲在數據庫中。
• 驗證用戶輸入。當將用戶輸入傳遞給 SQL 命令時,例如比較語句或模式匹配語句中的字符串,應非常小心地驗證此輸入,以確保最終的命令不包含語法錯誤,並且還要確保黑客不會使您的應用程序運行任意 SQL 命令。在登錄過程中驗證提供的用戶名特別重要,因為應用程序的安全模型完全取決於是否能夠正確而安全地對用戶進行身份驗證。
創建一個有登錄頁的 Web 應用程序
此過程創建一個簡單的 Visual C# Web 應用程序,它包含一個用戶可以輸入用戶名和密碼的登錄頁。
要創建一個有登錄頁的 Web 應用程序,請執行下列步驟:
• 啟動 Visual Studio .NET 並創建一個新的名為 FormsAuthSQL 的 Visual C# ASP.NET Web 應用程序。
• 使用解決方案資源管理器將 WebForm1.aspx 重命名為 Logon.aspx
• 將表 1 中列出的控件添加到 Logon.aspx 中來創建簡單的登錄窗體。
表 1:Logon.aspx 控件控件類型文本ID
Label
User Name:
-
Label
Password
-
Text Box
-
txtUserName
Text Box
-
txtPassword
Button
Register
btnRegister
Button
Logon
btnLogon
Label
-
lblMessage
您的 Web 頁應與圖 1 中所示的頁類似。
圖 1. 登錄頁 Web 窗體
• 將 txtPassword 的 TextMode 屬性設置為 Password。
配置 Web 應用程序進行 Forms 身份驗證
此過程編輯應用程序的 Web.config 文件來配置應用程序以進行 Forms 身份驗證。
要配置 Web 應用程序以進行 Forms 身份驗證,請執行下列步驟:
1. 使用解決方案資源管理器打開 Web.config。
2. 定位到 元素並將 mode 屬性更改為 Forms。
3. 將下列 元素作為 元素的子元素進行添加,並設置 loginUrl、name、timeout 和 path 屬性,如下所示:
ms loginUrl="logon.aspx" name="sqlAuthCookie" timeout="60" path="/">
4. 將下列 元素添加到 元素下這一步的目的是只允許經過身份驗證的用戶訪問應用程序。以前建立的 元素的 loginUrl 屬性將未經過身份驗證的請求重定向到 logon.aspx 頁。
開發生成哈希和 Salt 值的函數
此過程向 Web 應用程序添加兩個實用工具方法;一個方法生成一個隨機 salt 值,另一個方法根據提供的密碼和 salt 值創建哈希。
要開發生成哈希和 salt 值的函數,請執行下列步驟:
1. 打開 Logon.aspx.cs 並將下列 using 語句添加到位於文件頂部的現有 using 語句下。
using System.Security.Cryptography;
using System.Web.Security;
2. 將下列靜態方法添加到 WebForm1 類中,用於生成隨機 salt 值並作為 Base 64 編碼字符串返回此值。
private static string CreateSalt(int size)
{
// Generate a cryptographic random number using the cryptographic
// service provider
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
// Return a Base64 string representation of the random number
return Convert.ToBase64String(buff);
}
3. 添加下列靜態方法以根據提供的密碼和 salt 值生成哈希值。
private static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "SHA1");
return hashedPwd;
}
創建用戶帳戶數據庫
此過程在 SQL Server 中創建一個新的用戶帳戶數據庫,此數據庫包含一個用戶表和一個用於查詢用戶數據庫的存儲過程。
要創建用戶帳戶數據庫,請執行下列操作:
1. 在 Microsoft SQL Server programs 菜單上,單擊 Query Analyzer,然後連接到本地 SQL Server。
2. 輸入下列 SQL 腳本。注意,必須用自己的計算機名稱替換此腳本末尾的“LocalMachine”。
USE master
GO
-- create a database for the security information
IF EXISTS (SELECT * FROM master..sysda
tabases WHERE name = 'UserAccounts')
DROP DATABASE UserAccounts
GO
CREATE DATABASE UserAccounts
GO
USE UserAccounts
GO
CREATE TABLE [Users] (
[UserName] [varchar] (255) NOT NULL ,
[PasswordHash] [varchar] (40) NOT NULL ,
[salt] [varchar] (10) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
(
[UserName]
) ON [PRIMARY]
) ON [PRIMARY]
GO
-- create stored procedure to register user details
CREATE PROCEDURE RegisterUser
@userName varchar(255),
@passwordHash varchar(40),
@salt varchar(10)
AS
INSERT INTO Users VALUES(@userName, @passwordHash, @salt)
GO
-- create stored procedure to retrieve user details
CREATE PROCEDURE LookupUser
@userName varchar(255)
AS
SELECT PasswordHash, salt
FROM Users
WHERE UserName = @userName
GO
-- Add a login for the local ASPNET account
-- In the following statements, replace LocalMachine with your
-- local machine name
exec sp_grantlogin [LocalMachineASPNET]
-- Add a database login for the UserAccounts database for the ASPNET account
exec sp_grantdbaccess [LocalMachineASPNET]
-- Grant execute permissions to the LookupUser and RegisterUser stored procs
grant execute on LookupUser to [LocalMachineASPNET]
grant execute on RegisterUser to [LocalMachineASPNET]
3. 運行查詢來創建 UserAccounts 數據庫。
4. 退出 Query Manager。
使用 ADO.NET 將帳戶詳細信息存儲在數據庫中
此過程修改 Web 應用程序代碼,以將提供的用戶名、生成的密碼哈希和 salt 值存儲在數據庫中。
要使用 ADO.NET 將帳戶詳細信息存儲在數據庫中,請執行下列操作:
• 返回到 Visual Studio .NET 並雙擊 Web 窗體上的 Register 按鈕來創建按鈕單擊事件處理程序。
• 將下列代碼添加到方法中。
string salt = CreateSalt(5);
string passwordHash = CreatePasswordHash(txtPassword.Text,salt);
try
{
StoreAccountDetails( txtUserName.Text, passwordHash, salt);
}
catch(Exception ex)
{
lblMessage.Text = ex.Message;}
• 將下列 using 語句添加到位於文件頂部的現有 using 語句下。
using System.Data.SqlClient;
• 使用下列代碼添加 StoreAccountDetails 實用工具方法。此代碼使用 ADO.NET 連接到 UserAccounts 數據庫,並將提供的用戶名、密碼哈希和 salt 值存儲在 Users 表中。