1、浅谈使用 MD5 算法加密用户密码一、引言最近看了媒体的一篇关于“网络上公开叫卖个人隐私信息”报导,不法分子通过非法手段获得的个人隐私信息,其详细、准确程度简直令人瞠口结舌。在互联网飞速发展的现在,我们不难想到,网络肯定是传播这些个人隐私信息的重要途径之一。现在网络上一般的网站,只要稍微完善一点的,都需要用户进行注册,提供诸如用户名、用户密码、电子邮件、甚至是电话号码、详细住址等个人隐私信息,然后才可以享受网站提供的一些特殊的信息或者服务。比如电子商务网站,用户需要购买商品,就一定需要提供详细而准确的信息,而这些信息,往往都是用户的隐私信息,比如电子邮件、电话号码、详细住址等。所以,用户注册的
2、信息对于用户和网站来说都是很重要的资源,不能随意公开,当然也不能存在安全上的隐患。用户注册时,如果将用户资料直接保存在数据库中,而不施加任何的保密措施,对于一些文件型数据库(如 Access) ,如果有人得到这个数据库文件,那这些资料将全部泄露。再有,如果遇到一个不负责任的网管,则不需要任何技术手段,他就可以查看到用户的任何资料。所以,为了增加安全性,我们有必要对数据库中的隐私数据进行加密,这样,即使有人得到了整个数据库,如果没有解密算法,也一样不能查看到用户的隐私信息。但是,在考虑数据库是否安全之前,有必要对这些数据是否真的那么重要进行考虑,如果数据并不重要,则没有保密的必要,否则将会浪费系
3、统资源、加重程序负担。反之,如果数据具有一定的隐私性,则必须进行加密。因此,在考虑加密以前,应该对数据是否需要加密做出选择,以免浪费系统资源或者留下安全隐患。二、MD5 算法简介MD5 算法,即“Message-Digest Algorithm 5(信息-摘要算法) ”,它是由MD2、 MD3、 MD4 发展而来的一种单向函数算法,也就是哈希(HASH)算法,是由国际著名的公钥加密算法标准 RSA 的第一设计者 R.Rivest 于上个世纪 90 年代初开发出来的。加密算法一般有两种,即单向加密算法和双向加密算法。双向加密是加密算法中最常用的,它将可以直接理解的明文数据加密为不可直接理解的密文
4、数据,在需要的时候,又可以使用一定的算法将这些加密以后的密文数据解密为原来的明文数据。双向加密适合于隐秘通讯,比如,比如在网络上注册用户或者购买商品时,提交的真实姓名、身份证号码、银行账号、信用卡密码等信息,应当通过双向加密算法加密以后,再在网络上传输,这样,可以有效的防止黑客的“偷听” ,保证数据的安全,同时,网站接收到我们的数据以后,可以通过解密算法来获得准确的信息。双向加密既可以加密,又可以解密。而单向加密则刚好相反,它只能对明文数据进行加密,而不能对加密了的密文数据再解密成原来的明文数据。可能读者会认为,不能解密的加密算法有什么作用呢?在实际应用中,对软件系统数据库中的系统用户信息(如
5、用户密码)加密,就是一个典型的例子。当用户注册一个新的账号时,其用户密码信息不是直接保存到数据库,而是经过单向加密后再保存,这样,即使这些账号信息被泄露,别人也不能得到相应的用户密码,当然也就达不到盗窃账号的目的。MD5 算法就是单向加密的加密算法。它有两个很重要的特性,第一是任意两段明文数据,加密以后的密文数据一定是不相同的;第二是任意一段明文数据,经过加密以后,其密文数据永远是相同的。三、在 C# 中使用 MD5 算法加密用户密码为了更好的说明 MD5 算法的实际应用,下面用一个实例来进行介绍。该实例使用 MD5算法加密软件系统的系统用户密码。该实例用到的软件有: Microsoft SQ
6、L Server 2000 Microsoft Visual Studio 2005本实例使用 C# 语言开发,并采用 Windows 应用程序的形式给出。具体的实现方法和步骤如下:(1)使用 Microsoft SQL Server 2000 创建一个名为 “DBMD5”数据库,并在“DBMD5”数据库中创建一个名为“tbl_User”的数据表,数据表的结构如下表所示(非本文重点,不作具体介绍) 。列名 说明 数据类型 约束userId 用户名 varchar,长度为 32 主键userPsw 用户密码 varchar,长度为 32 非空(2)使用 Microsoft Visual Stud
7、io 2005 创建一个名为 “UseMd5”的 Visual C# Windows应用程序,并将默认的窗体界面设计成如下图所示。(3)窗体和窗体中的各对象属性设置如下表所示。控件类型 控件名称 属性 设置结果Name FrmLoginText 登录StartPosition CenterScreenForm Form1MaximizeBox FalseLabel1 Text 用户名LabelLabel2 Text 用户密码TextBox1 Name txtIdName txtPswTextBoxTextBox2PasswordChar *Name btnLoginButton1Text 登录
8、Name btnCancelButton2Text 取消Name btnRegeditButtonButton3Text 注册(4)接下来引入几个命名空间,定义公共变量和对象,并编写一个用于加密数据的公共方法。首先引入以下两个命名空间,其中“System.Data.SqlClient ”是访问 SQL 数据库所需的,而“System.Security.Cryptography”则包含了与 MD5 算法相关的类。/ *using System.Data.SqlClient;using System.Security.Cryptography;/ *然后定义以下公共变量和对象,其中静态字符串变量“
9、connStr ”用于指定数据库连接字符串, “conn”是 SQL 数据库连接对象。/ *public string connStr = “server=服务器名称;database=数据库名称;integrated security=SSPI“;SqlConnection conn = new SqlConnection(connStr);/ *接下来编写一个名为“GetMd5Str()”的方法,并给该方法定义一个字符串类型的形式参数“myString ”,该方法用来将指定的字符串“myString”使用 MD5 算法进行加密,并返回加密后的密文数据字符串。/ *public string
10、 GetMd5Str(string myString)MD5 md5 = new MD5CryptoServiceProvider();byte fromData = System.Text.Encoding.Unicode.GetBytes(myString);byte toData = md5.ComputeHash(fromData);string byteStr = null;for (int i = 0; i toData.Length; i+)byteStr += toDatai.ToString(“x“);return byteStr.Substring(0, 32);/ *上述
11、代码中, “MD5CyptoServiceProvider”类是.NET 中“System.Security.Cryptography”命名空间的一个类,提供专门用于 MD5 单向数据加密的解决方法,也是本文中用来加密数据库中用户密码的类。在使用“GetMd5Str()”方法进行数据加密之前,我们首先来了解“MD5CyptoServiceProvider”类的主要方法:ComputeHash()方法。ComputeHash()方法用来将输入的明文数据字符数组使用 MD5 进行加密,然后输出加密后的密文数据字符数组。在“GetMd5Str()”方法中:要加密的明文字符串为“myString” ;
12、用于存放明文字符串的字符数组为“fromData” ;用于接收密文数据的字符数组为“toData” ;方法的返回值为密文字符串“byteStr”的前 32 位。可以看出, “ComputeHash()”方法只能接受数组作为加密对象,输出的密文也是数组,因此,在对字符串加密之前,我们必须首先将字符串转化为字符数组,这就要用到“Encoding”类的 GetBytes 方法,将字符串转化为字符数组,而加密以后的结果也是使用字符数组输出。(5)编写【取消】按钮的单击事件代码当用户单击【取消】按钮时,即终止登录操作,并关闭登录界面,因此需要编写【取消】按钮的单击事件代码如下:/ *private vo
13、id btnCancel_Click(object sender, EventArgs e)Application.Exit();/ *(6)编写【注册】按钮的单击事件代码当用户注册用户账号时,数据库中就需要为这个用户增加一条相应的记录。下面的程序代码实现了创建一个账号的功能,只要用户输入用户名、用户密码信息后单击【注册】按钮,就可以将这些信息存入到“DBMD 5”数据库的“tbl_User”数据表中,在这个表中,用户密码是使用 MD5 加密保存的。具体的代码如下:/ *private void btnRegedit_Click(object sender, EventArgs e)tryif
14、 (txtId.Text.Trim() = “)MessageBox.Show(“用户名不能为空!“);txtId.Focus();else if (txtPsw.Text.Trim() = “)MessageBox.Show(“密码不能为空!“);txtPsw.Focus();elsestring psw = GetMd5Str(txtPsw.Text.Trim();string sqlStr = “insert into tbl_User values(“ + txtId.Text.Trim() + “,“ + psw.Trim() + “)“;SqlCommand cmd = new S
15、qlCommand(sqlStr, conn);cmd.CommandType = CommandType.Text;conn.Open();cmd.ExecuteNonQuery();conn.Close();MessageBox.Show(“注册成功!“);catch (Exception ex)MessageBox.Show(ex.Message);/ *由代码可知, “userPsw”字段的信息是 MD5 加密方式保存的,即使数据库被人取得,也不可能知道用户密码具体是什么,当然,账号信息也就不会泄露。(7)编写【登录】按钮的单击事件代码既然用户密码是按照 MD5 加密以后保存在数据库中
16、的,而前面介绍过,MD5 是单向加密算法,所以,不可能将加密以后的信息转为明文,也就是说,已经没有办法知道用户密码是什么。这就出现一个问题,如果用户使用账号、密码登录系统,怎么知道用户提供的密码是否准确,从而通过系统的身份验证呢?前面已经介绍过 MD5 算法的特征,任意一段明文数据,经过 MD5 加密以后的结果是永远不变的,也就是说,如果需要验证用户密码是否正确,只需要将用户当前提供的密码使用 MD5 加密,然后和数据库中保存的密码值进行比较就可以了。下面是【登录】按钮的单击事件代码,用来实现用户登录的功能:/ *private void btnLogin_Click(object sende
17、r, EventArgs e)tryif (txtId.Text.Trim() = “)MessageBox.Show(“用户名不能为空!“);txtId.Focus();else if (txtPsw.Text.Trim() = “)MessageBox.Show(“密码不能为空!“);txtPsw.Focus();elsestring sqlStr = “select userPsw from tbl_User where userId=“ + txtId.Text.Trim() + “;SqlCommand cmd = new SqlCommand(sqlStr, conn);conn.
18、Open();SqlDataReader sdr = cmd.ExecuteReader();if (sdr.Read()string psw = GetMd5Str(txtPsw.Text.Trim();if (sdr“userPsw“.ToString().Trim() = psw.Trim()conn.Close();MessageBox.Show(“登录成功!“);elseconn.Close();MessageBox.Show(“密码错误,请重新输入!“);txtPsw.Text = “;txtPsw.Focus();elseconn.Close();MessageBox.Show(
19、“用户名错误,请重新输入!“);txtId.Text = “;txtPsw.Text = “;txtId.Focus();catch (Exception ex)MessageBox.Show(ex.Message);/ *看过登录代码,也许有的读者会想,黑客们盗取到用户信息后,仍然有可能先猜密码,再将猜测的密码通过 MD5 加密,然后用这个密文数据跟数据库中的核对,从而盗取用户账号。其实,解决这个问题的办法很简单,对于那些绝密的数据,可以通过多次加密来保存,这样,被破解的几率就几乎为零了。四、结束语也许,有的读者会想,既然密码无法解密,那用户一旦忘记了密码,几乎没有办法找回原来的密码,又该怎么办呢?这确实是一个比较麻烦的问题,如果是一个功能简单的软件系统,也许真的只能删除忘记密码的账号信息,然后再重新注册来解决。但是比较完善的软件系统,一般都可以让用户提供一些其他的注册信息,如出生地址、父母妻子的职业等,如果正确,则直接给用户提供修改密码的功能,然后用新密码替换掉数据库中的旧密码,这样,用户只要记住新的用户密码就可以了。本文详细介绍了使用 MD5 加密用户密码的实现方法,同时,也介绍了采用加密密码方式以后,用户身份验证的实现。并且讨论了使用这种加密方式的应用限制。在实际应用中,应当将此方法做适当的修改和补充,以更加适合应用的需要。