惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
B
Blog RSS Feed
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
MyScale Blog
MyScale Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
Y
Y Combinator Blog
月光博客
月光博客
IT之家
IT之家
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
L
LangChain Blog
博客园_首页
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
博客园 - Franky
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
M
MIT News - Artificial intelligence
V
Visual Studio Blog
小众软件
小众软件
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
N
Netflix TechBlog - Medium

博客园 - 博客人

Asp.net2.0页面的生命周期 写有效率的SQL查询(V) aspx页面事件执行顺序 如何从优化SQL入手提高数据仓库的ETL效率(转载) 简单的3个SQL视图搞定所有SqlServer数据库字典 (转载) IIS的各种身份验证详细测试 .Net专题(C# 中的委托和事件) - Part.1 创建X509证书,并获取证书密钥的一点研究 Url重写 asp.net中数据校验部分的封装与应用 SQL Server 索引结构及其使用(一) asp.net2.0导出pdf文件完美解决方案 Web Service 中的身份验证策略--使用自定义SOAP 标题 ASP.NET 2.0加密Web.config 配置文件 WebService中使用自定义类的解决方法(5种) MS-SQL数据库开发常用汇总和t-sql技巧集锦 [原创] 如何追踪每一笔记录的来龙去脉:一个完整的Audit Logging解决方案—Part I 通用异常处理框架 如何使用.NET配置文件(转载)
Web Service Authentication + MD5 [from]
博客人 · 2007-05-24 · via 博客园 - 博客人

Sample Image - WebServiceAuthentication.gif

Introduction

This is a simple mechanism to authenticate users to a Web Service, using a Time Token and MD5 Hashing to encrypt password.

Background

In CodeProject, you can find at least two others' mechanism to authenticate users to a Web Service. Dan_P wrote Authentication for Web Services as a Simple authentication for web services using SOAP headers. But the username and password are send in clear text and there is no encryption for the data. HENDRIK R. is the author of An introduction to Web Service Security using WSE, that is really a complete solution, but too much complicated for my purposes. The username is send in clear text, but it is possible to use Password Digest to encrypt the password. The data are encrypted using XML Encryption specification to encrypt portions of the SOAP messages.

My solution is something in the middle of the above two. The username is send in clear text, but I use MD5 to encrypt the password. I do not need to send sensitive data, so the data returned by the Web Service is not encrypted.

Using the code

The basic idea is to send UserName and Password from the client to the Web Service using MD5 Hash Code as encryption system. In this way, the password never travels in clear over the network. The Web Service retrieves the user password from a DB or anything else and uses the same MD5 algorithm to test if the password is correct. To be sure that if someone intercepts the Hash, this can be used to authenticate in a later time, I added a timestamp before hashing the Key string. Last, as we are not always on the same server and/or the client clock may be in a different Time Zone or simply not synchronized, I added the possibility to request a Token containing the time mark to the server.

I provided a sample in ASP.NET C# for the client side, but it is possible to use any language: ASP classical JScript or VBScript, PHP, Python, etc. Anyway, on the client side we need to build up the Key using UserName, Password and the hashed timestamp Token previously got from the same Web Service. We can then call the Service and we will get the answer (or an authentication failure warning) that is displayed on the web page.

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;
}

The MD5 Hash procedure is very simple in C#; this one was written by Vasudevan Deepak Kumar in Securing Web Accounts.

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, 0true);

    
// This is one implementation of the abstract class MD5.
    MD5 md5 = new MD5CryptoServiceProvider();
    
byte[] result = md5.ComputeHash(data);

    
return BitConverter.ToString(result).Replace("-""").ToLower();
}

On Web Service server side I implemented just three Web Methods:

GetToken is used to get the Time-marked token. The token you get this way, is intended to be used in the basic Authenticate method, or in the UseService that can also verify the access rights for the users authenticated to the requested service. The core of the system is implemented by TestHash. Here the password is hard-coded, but in the sample provided you have also the code to get it from a database:

Collapse

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;
    }

}

To request a hashed time-stamped Token to the Web Service the method is:

[WebMethod]
public string GetToken ()
{
    
string ToHash, sResult;
    DateTime dt 
= DateTime.Now;
    ToHash
=dt.ToString("yyyyMMdd")+"|"+dt.ToString("HHmm");
    sResult 
= Hash(ToHash);
    
return sResult;
}

The method that checks the user authentication is also kept very simple; in a real application you normally need to access a database to check the authentication level and may need to return some data to the caller:

Collapse

[WebMethod]
public string UseService (string Key, string ServiceName)
{
    
string [] HashArray;
    
string UserName, level;

    
// Key string: HASH|User|OptionalData
    HashArray=Key.Split('|');
    level 
= "-1";    //defaul 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/shuold 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";
}

Points of Interest

TestHash checks to see if the Hash contains a timestamp or an already-hashed token, and calls itself once again in case of failure: if someone is calling the service, let's say, at 11:34:58 the Key is valid from 11:34:00 until 11:35:00, that is during two minutes.

The client side may be implemented in any language: ASP classical, JScript or VBScript, PHP, Python, etc. I have intention to post this code too next time...