用RSA加密实现Web登录密码加密传输

用RSA加密实现Web登录密码加密传输

通常我们做一个Web应用程序的时候都需要登录,登录就要输入用户名和登录密码,并且,用户名和登录密码都是明文传输的,这样就有可能在中途被别人拦截,尤其是在网吧等场合。

这里顺带一个小插曲,我以前有家公司,办公室装修时候安排的网口相对较少,不太够用,于是我和另外一个同事使用了一个hub来共享一个网口,这就导致了很有趣的现象:任何他的网络包我都能抓得到,当然了,我的他也能抓得到。这是不是有很大的安全隐患了?我有可能在不经意间会泄漏自己的密码。

所以,很多安全要求较高的网站都不会明文传输密码,它们会使用https来确保传输过程的安全,https是用证书来实现的,证书来自于证书颁发机构,当然了,你也可以自己造一张证书,但这样别人访问你的网站的时候还是会遇到麻烦,因为你自己造的证书不在用户浏览器的信任范围之内,你还得在用户浏览器上安装你的证书,来让用户浏览器相信你的网站,很多用户并不知道如何操作,就算会操作,也能也不乐意干;另一种选择是你向权威证书颁发机构申请一张证书,但这样有一定的门槛,还需要付费,也不是我们乐意干的事。

所以,我打算自己实现一个密码加密传输方法。

这里使用了RSA非对称加密算法,对称加密也许大家都已经很熟悉,也就是加密和解密用的都是同样的密钥,没有密钥,就无法解密,这是对称加密。而非对称加密算法中,加密所用的密钥和解密所用的密钥是不相同的:你使用我的公钥加密,我使用我的私钥来解密;如果你不使用我的公钥加密,那我无法解密;如果我没有私钥,我也没法解密。

我设计的这个登录密码加密传输方法的原理图如下:

首先,先演练一下非对称加密:

static void Main(string[] args){    //用于字符串和byte[]之间的互转    UTF8Encoding utf8encoder = new UTF8Encoding();

//产生一对公钥私钥    RSACryptoServiceProvider rsaKeyGenerator = new RSACryptoServiceProvider(1024);    string publickey = rsaKeyGenerator.ToXmlString(false);    string privatekey = rsaKeyGenerator.ToXmlString(true);

//使用公钥加密密码    RSACryptoServiceProvider rsaToEncrypt = new RSACryptoServiceProvider();    rsaToEncrypt.FromXmlString(publickey);    string strPassword = "@123#abc$";    Console.WriteLine("The original password is: {0}", strPassword);    byte[] byEncrypted = rsaToEncrypt.Encrypt(utf8encoder.GetBytes(strPassword), false);    Console.Write("Encoded bytes: ");    foreach (Byte b in byEncrypted)    {        Console.Write("{0}", b.ToString("X"));    }    Console.Write("\n");    Console.WriteLine("The encrypted code length is: {0}", byEncrypted.Length);

//解密    RSACryptoServiceProvider rsaToDecrypt = new RSACryptoServiceProvider();    rsaToDecrypt.FromXmlString(privatekey);    byte[] byDecrypted = rsaToDecrypt.Decrypt(byEncrypted, false);    string strDecryptedPwd = utf8encoder.GetString(byDecrypted);    Console.WriteLine("Decrypted Password is: {0}", strDecryptedPwd);}

大家可以清楚看到,密码被加密成128字节长度的密文,为什么是固定128字节呢?这是因为我们的RSACryptoServiceProvider默认生成的key的长度是1024,即1024位的加密,所以不管你要加密的密码有多长,它生成的密文的长度肯定是128字节,也因为这样,密码的长度是有限制的,1024位的RSA算法,只能加密大约100个字节长度的明文,要提高可加密的明文的长度限制,就得增加key的长度,比如把key改到2048位,这样能加密的明文的长度限制也就变为大概200出头这样……还是太少啊!而且这样会带来加密速度的显著下降,RSA本来就很慢……是的,比同没有长度限制的对称加密,这种非对称加密的限制可真多,即便是200个字符,又能传输什么东西呢?——密码!这个就够了,传输完密码之后,我们就使用对称加密,所以,RSA往往是用来“协商”一个对称加密的key的。

接下去,真正的难点在于用javascript实现一个和.net的RSA兼容的算法。密码学,对我来说真像天书一般,每次我一看就头大,这个工作是没办法自己做的了,只能到网上找,那是相当的费力啊,找到许多js的RSA实现,但都和.net的这套东西不兼容,最后还是功夫不负有心人,终于找到了一套。不多说,上代码:

<html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>RSA Login Test</title>    <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>    <script src="Scripts/jQuery.md5.js" type="text/javascript" ></script>    <script src="Scripts/BigInt.js" type="text/javascript"></script>    <script src="Scripts/RSA.js" type="text/javascript"></script>    <script src="Scripts/Barrett.js" type="text/javascript"></script>    <script type="text/javascript">        function cmdEncrypt() {            setMaxDigits(129);            var key = new RSAKeyPair("<%=strPublicKeyExponent%>", "", "<%=strPublicKeyModulus%>");            var pwdMD5Twice = $.md5($.md5($("#txtPassword").attr("value")));            var pwdRtn = encryptedString(key, pwdMD5Twice);            $("#encrypted_pwd").attr("value", pwdRtn);            $("#formLogin").submit();            return;        }    </script>

</head><body>    <form action="Default.aspx" id="formLogin" method="post">    <div>        <div>            User Name:        </div>        <div>            <input id="txtUserName" name="txtUserName" value="<%=postbackUserName%>" type="text" maxlength="16" />        </div>        <div>            Password:        </div>        <div>            <input id="txtPassword" type="password" maxlength="16" />        </div>        <div>            <input id="btnLogin" type="button" value="Login" onclick="return cmdEncrypt()" />        </div>    </div>    <div>        <input type="hidden" name="encrypted_pwd" id="encrypted_pwd" />    </div>    </form>    <div>        <%=LoginResult%>    </div></body></html>

这是客户端代码,大家可以看到,基本没有什么服务器端代码,<%=postbackUserName%>用于回显输入的用户名,<%=LoginResult%>用于显示登录结果,<%=strPublicKeyExponent%>和<%=strPublicKeyModulus%>则用来告诉客户端RSA公钥。需要的javascript文件说明:

  • jQuery.md5.js -  用于对密码进行两次md5加密;(我通常在数据库中保存的用户密码是两次MD5后的结果)
  • BigInt.js - 用于生成一个大整型;(这是RSA算法的需要)
  • RSA.js - RSA的主要算法;
  • Barrett.js - RSA算法所需要用到的一个支持文件;

对于密码学,我几乎一无所知,所以没办法跟大家解释清楚RSA算法的原理,抱歉,我只知道怎么用。关于javascript中这行代码:“setMaxDigits(129);”具体表示什么我也不清楚,我只知道,把参数改为小于129的数之后会导致客户端的javascript执行进入死循环。服务器端代码也很简单:

protected void Page_Load(object sender, EventArgs e){    LoginResult = "";    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();    if (string.Compare(Request.RequestType, "get", true)==0)    {        //将私钥存Session中        Session["private_key"] = rsa.ToXmlString(true);    }    else    {        bool bLoginSucceed = false;        try        {            string strUserName = Request.Form["txtUserName"];            postbackUserName = strUserName;            string strPwdToDecrypt = Request.Form["encrypted_pwd"];            rsa.FromXmlString((string)Session["private_key"]);            byte[] result = rsa.Decrypt(HexStringToBytes(strPwdToDecrypt), false);            System.Text.ASCIIEncoding enc = new ASCIIEncoding();            string strPwdMD5 = enc.GetString(result);            if (string.Compare(strUserName, "user1", true)==0 && string.Compare(strPwdMD5, "14e1b600b1fd579f47433b88e8d85291", true)==0)                bLoginSucceed = true;        }        catch (Exception)        {

}        if (bLoginSucceed)            LoginResult = "登录成功";        else            LoginResult = "登录失败";    }

//把公钥适当转换,准备发往客户端    RSAParameters parameter = rsa.ExportParameters(true);    strPublicKeyExponent = BytesToHexString(parameter.Exponent);    strPublicKeyModulus = BytesToHexString(parameter.Modulus);}

用户名“user1”
密码“123456”

登录成功!

抓取http报文看看POST的“密码”:

这样的“密码”的破解就成为了理论上的可行了。:)

下面提供完整代码下载(使用VS2010开发环境):

http://files.cnblogs.com/guogangj/RSALoginTest.zip

原文地址:http://www.cnblogs.com/guogangj/archive/2012/03/05/2381117.html

时间: 2024-10-18 13:56:13

用RSA加密实现Web登录密码加密传输的相关文章

MVC扩展Filter,通过继承ActionFilterAttribute为登录密码加密

与ActionFilter相关的接口有2个: □ IActionFilter 对action执行前后处理 void OnActionExecuting(ActionExecutingContext filterContext);可以在此对请求处理,甚至开启一个新的请求. void OnActionExecuted(ActonExecutedContext filterContext);可以在此对返回结果处理,甚至取消返回结果. 关于参数ActionExecutingContext和ActonEx

用户登录密码加密

用户登录密码加密 用Windows自带的MD5,一般来说就差不多了 public String makeMD5(String password) { MessageDigest md;    try {     // 生成一个MD5加密计算摘要     md = MessageDigest.getInstance("MD5");     // 计算md5函数     md.update(password.getBytes());     // digest()最后确定返回md5 has

laravel更改默认的登录密码加密方式

laravel 默认用的登录密码加密方式是: $password = Hash::make('password'); 而我平时用的密码加密方式是: $password = md5('password'.'salt'); //其中的salt是一个随机串 那么怎么把默认的改成自己想要的呢? 我谷歌了一下,还真让我找到了.转送:http://blueve.me/archives/898 为了防止这个网站打不开,我自己再稍微整理了一下,以备后用: 首先,打开这个文件夹:/vender/laravel/f

基于RSA的WEB前端密码加密方案

受制于WEB页面源码的暴露,因此传统的对称加密方案以及加密密钥都将暴露在JS文件中,同样可以被解密. 目前比较好的解决方案是WEB页面全程或用户登录等关键环节使用HTTPS进行传输. 另外一种解决方案就是通过RSA进行加密. RSA是一种非对称加密,也就是客户端通过公钥进行加密,服务端通过私钥进行解密.RSA算法请点击百度百科进行了解. 也就是说公钥并不能进行解密,因此进行明文传输也是安全的. 1.加密流程 服务端生成一组公钥与私钥,将公钥发送给客户端进行密码加密,在使用密钥进行解密. 2.密钥

前端登录密码加密传输

目的:防止登录密码名文传输(仅仅只是防止明文传输,加密效果取决于key,而key对于前台是透明的) 方式:前端页面用js加密前端登录密码,采用AES对称加密 一.前端JS加密库crypto-js 因为懒,所以直接引入整个加密库,可以根据所需要的加密算法分别引入,下载地址crypto-js 如果是分别引入,记得别忘记引入核心库core 二.前端页面代码 因为需要加密密码,所以把提交方式换成了ajax AES加密的key为128bit,可以理解为16个字符.key由后端生成并送入前端. <!DOCT

jmeter登录密码加密,使用jar包方式 12

现在很多的接口,例如登录密码会通过后台代码自动进行加密,但是在jmeter中如果我们没有引入加密过程的代码,就需要自己通过抓包的方式获取加密后的 密码才可以登录成功,为了方便我们可以通过引入代码的方式快速登录.下面简单介绍两种: 方式一:使用base64,函数助手方式 使用jmeter自带的加密方法 方式二:使用jar包方式,引入beanshell预处理 开发给我们一个.java包,在我们不确认自己可以一次性导入引用成功的前提下,可以先将需要的代码写入到eclipse进行校验,运行处正确的结果后

页面登录密码加密传输机制

为了避免用户密码使用明文传输,在传输前需要进行加密处理,服务端接收之后再进行解密,这样从一定程度上保护了密码安全. 基本过程如下: 显然,采用非对称加密更合适,这里我们使用RSA加密算法. 需要三方面的东东. 第一样,服务器端RSA加解密工具类及KEY定义. 第二样,Web端RSA加密工具类,支持根据公钥加密. 第三样,用户登录时的处理脚本. 赋代码是直接的 Case one 1 namespace Tool.Security 2 { 3 /// <summary> 4 /// 对公钥的提供和

RSA非对称算法实现HTTP密码加密传输

目前一般帐号系统,都是https来传输账户性息,申请一个https证书也不贵.但是网站的其它功能并不需要走https协议,https和http混布比较麻烦,所以决定先实现一个http协议传输RSA非对称密钥算法加密密码的方案.这样做只能说是保证不明文传密码,但是并不能防身份伪造,所以其实还是不安全的,只是目前产品能接受,算是一个过渡期吧.有需要的话还是要改成https的. 关于rsa算法,具体参考维基百科相关的介绍.简单来说,用rsa算法产生一对公钥和私钥,通信双方A和B,A用公钥加密要发送的数

SpringSecurity 3.2入门(4)登录密码加密

密码admin 进行MD5 32位加密为21232F297A57A5A743894A0E4A801FC3 增加spring-security.xml文件配置如下 <!-- 认证管理器,配置SpringSecutiry的权限信息 --> <security:authentication-manager> <security:authentication-provider> <!-- 帐户信息,指定用户名.密码和权限 --> <security:user-