Web 服务身份验证
一种简单地验证用户是否可以访问 WebService 的机制
引言
这是一个简单的机制,用于通过使用时间令牌和 MD5 哈希来加密密码,对 Web 服务进行用户身份验证。
背景
在 CodeProject 中,您可以找到至少两种其他机制来对 Web 服务进行用户身份验证。Dan_P 编写了 用于 Web 服务的身份验证作为使用 SOAP 标头的 Web 服务的简单身份验证。 但是用户名和密码以明文形式发送,并且没有对数据进行加密。HENDRIK R. 是 使用 WSE 进行 Web 服务安全性简介的作者,这确实是一个完整的解决方案,但对于我的目的而言过于复杂。 用户名以明文形式发送,但是可以使用密码摘要来加密密码。 数据使用 XML 加密规范进行加密,以加密 SOAP 消息的各个部分。
我的解决方案介于上述两者之间。 用户名以明文形式发送,但是我使用 MD5 加密密码。 我不需要发送敏感数据,因此 Web 服务返回的数据未加密。
Using the Code
基本思想是使用 MD5 哈希代码作为加密系统,将 UserName
和 Password
从客户端发送到 Web 服务。 这样,密码永远不会在网络上以明文形式传输。 Web 服务从数据库或其他任何地方检索用户密码,并使用相同的 MD5 算法来测试密码是否正确。 为了确保如果有人拦截了哈希,则可以用来在以后的时间进行身份验证,我在哈希 Key
字符串之前添加了一个时间戳。 最后,由于我们并不总是在同一台服务器上,并且/或者客户端时钟可能位于不同的时区或者只是未同步,因此我添加了请求包含服务器时间标记的令牌的可能性。
我提供了 ASP.NET C# 中的客户端示例,但是可以使用任何语言:ASP 经典 JScript 或 VBScript,PHP,Python 等。 无论如何,在客户端,我们需要使用 UserName
、Password
和先前从同一 Web 服务获得的哈希时间戳 Token
来构建 Key
。 然后,我们可以调用该服务,我们将获得在网页上显示的答案(或身份验证失败警告)。
private void ButtonUseToken_Click(object sender, System.EventArgs e)
{
string ret;
string UserName, Password, ServiceName, Token;
string Key, ToHash;
UserName=this.TextBoxUserName.Text;
Password=this.TextBoxPwd.Text;
ServiceName=this.TextBoxService.Text;
Token=this.TextBoxToken.Text;
ToHash=UserName.ToUpper()+"|"+Password+"|"+Token;
Key=Hash(ToHash)+"|"+UserName;
ServicePointReference.ServicePoint Authenticate =
new ServicePointReference.ServicePoint();
ret=Authenticate.UseService(Key, ServiceName);
this.ServResponse.Text=ret;
}
C# 中的 MD5 Hash
过程非常简单; 这是由 Vasudevan Deepak Kumar 在 保护 Web 帐户中编写的。
private string Hash(string ToHash)
{
// First we need to convert the string into bytes,
// which means using a text encoder.
Encoder enc = System.Text.Encoding.ASCII.GetEncoder();
// Create a buffer large enough to hold the string
byte[] data = new byte[ToHash.Length];
enc.GetBytes(ToHash.ToCharArray(), 0, ToHash.Length, data, 0, true);
// This is one implementation of the abstract class MD5.
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(data);
return BitConverter.ToString(result).Replace("-", "").ToLower();
}
在 Web 服务服务器端,我仅实现了三种 Web 方法
GetToken
用于获取带有时间标记的令牌。 您以这种方式获得的令牌旨在用于基本 Authenticate
方法中,或者用于 UseService
中,后者也可以验证对请求的服务进行身份验证的用户的访问权限。 该系统的核心由 TestHash
实现。 在这里,密码是硬编码的,但是在提供的示例中,您还可以找到从数据库中获取密码的代码
private bool TestHash (string HashStr,
string UserName, int minutes, string ServiceName)
{
string Pwd, ToHash;
string sResult, sResultT, sResultToken;
try
{
// JUST FOR TEST: the password is hard-coded:
Pwd="SeCrEt";
DateTime dt = DateTime.Now;
System.TimeSpan minute = new System.TimeSpan(0,0,minutes,0,0);
dt = dt-minute;
//before hashing we have:
//USERNAME|PassWord|YYYYMMDD|HHMM
ToHash=UserName.ToUpper()+"|"+Pwd+"|"+dt.ToString("yyyyMMdd")+
"|"+dt.ToString("HHmm");
sResult = Hash(ToHash);
//TokenWeGotBefore
ToHash=dt.ToString("yyyyMMdd")+"|"+dt.ToString("HHmm");
sResultToken = Hash(ToHash);
//USERNAME|PassWord|TokenWeGotBefore
ToHash=UserName.ToUpper()+"|"+Pwd+"|"+sResultToken;
sResultT = Hash(ToHash);
if ((sResult==HashStr) || (sResultT==HashStr))
return true;
else
if (minutes==0) // allowed max 2 minutes - 1
// second to call web service
return TestHash (HashStr, UserName, 1, ServiceName);
else
return false;
}
catch
{
return false;
}
}
要向 Web 服务请求哈希的时间戳记令牌,该方法是
[WebMethod]
public string GetToken ()
{
string ToHash, sResult;
DateTime dt = DateTime.Now;
ToHash=dt.ToString("yyyyMMdd")+"|"+dt.ToString("HHmm");
sResult = Hash(ToHash);
return sResult;
}
检查用户身份验证的方法也保持非常简单; 在实际应用程序中,您通常需要访问数据库以检查身份验证级别,并且可能需要将一些数据返回给调用方
[WebMethod]
public string UseService (string Key, string ServiceName)
{
string [] HashArray;
string UserName, level;
// Key string: HASH|User|OptionalData
HashArray=Key.Split('|');
level = "-1"; //default level
if (TestHash(HashArray[0], HashArray[1], 0, ServiceName))
{
try
{
UserName=HashArray[1];
// JUST FOR TEST: the User authentication level is hard-coded
// but may/should be retrieved from a DataBase
switch (UserName)
{
case "MyUserName":
level="1";
break;
case "OtherUser":
level="2";
break;
default:
level="-1";
break;
}
if (level=="1") return "YOU ARE AUTHORIZED";
}
catch (Exception exc)
{
return "Authentication failure: " + exc.ToString();
}
}
return "Authentication failure";
}
关注点
TestHash
检查 Hash
是否包含时间戳或已哈希的令牌,并且在失败的情况下再次调用自身:如果有人(例如)在 11:34:58 调用该服务,则 Key
从 11:34:00 到 11:35:59 有效,即在两分钟减去一秒的时间内有效。
客户端可以用任何语言实现:ASP 经典、JScript 或 VBScript、PHP、Python 等。 我打算下次也发布此代码……
历史
- 2005 年 1 月 20 日 - 创建文章
- 2009 年 11 月 25 日 - 更新了源代码