Web应用中保证密码传输安全

简介:
+关注继续查看

 去年写过一篇博文《Web应用的安全的登录认证》,使用HMAC的加密算法保证了在登录时的密码安全。虽然没看到有人质疑,但这里至少会引出一个问题:登录过程不需要将密码原文提交到服务器,但注册和修改密码这两个需要将密码原文提交到服务器的过程怎么办?


  解决这一问题最佳方案当然是使用非对称加密。简单的说,非对称加密算法需要两个密钥,分别称为公钥和私钥,其中公钥会被公布出来,而私钥由个了保管(就像保管自己的密码一样)。使用公钥加密的数据是不能用公钥解密的,只能由私钥来解密。如果将私钥保存在服务器,把公钥发送给浏览器对密码原文进行加密,那么加密后的数据在传输过程中是安全的,因为私钥始终不会出现在传输过程,这个加密数据就不能轻松的解开。关于非对称加密的知识,学霸们请去各种百科上搜索,这里就不多说了。


  目前最常用的非对称加密算法是RSA算法,在服务器端.NET、Java都支持,PHP也有组件支持。在浏览器端,也有JavaScript的RSA算法包——用Google搜索“javascript rsa”第一个结果就是“RSA In JavaScript - ohdave.com”,该网站提供了三个JS文件,BitInt.js、Barrett.js和RSA.js,这三个JS文件要在见面中按顺序引用。


  下面就以C#和JavaScript为例说明一下加密传输密码和后台解密的过程。


  当然第一步是要产生公钥和私钥,自己用C#写个小小的控制台程序或者Windows程序就能解决这个问题,顺便熟悉一下C#的RSA。顺便说一下,维基百科提到,要保证安全至少得使用1024位的Key,.NET的RSA支持384到2048位的Key,这里就以1024位为例吧,下面的程序会在执行目录输出一个key.xml文件,保存了产生的公钥和私钥


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[STAThread]
static void Main(string[] args)
{
    string keyFileName
        = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
            "key.xml";
    const int keySize = 1024;
    // 这个类在System.Security.Cryptography命名空间中
    RSACryptoServiceProvider sp = new RSACryptoServiceProvider(keySize);
    // 参数true表示XML中包含私钥。如果给false表示只生成公钥的XML
    string str = sp.ToXmlString(true);
    using (TextWriter writer = new StreamWriter(keyFileName)) {
        writer.Write(str);
    }
}


  打开生成的key.xml可以看到,这个Key值包含了如下几个部分:Modulus、Exponent、P、Q、DP、DQ、InverseQ、D。这几个部分的值都是以Base64编码保存的。其中,Modulus和Exponent就是组成公钥的部分,也就是需要传递给浏览器,简称M和E,用于加密的两个数值。


  生成key.xml之后,有两种方式使用,一种是在使用时从XML文件导入;另一种方式是把这几个值提取出来写在某个类中。导入XML需要先将XML文本读取到一个string中,再用RSACryptoServiceProvider的实例方法FromXmlString(string)导入。因为需要向浏览器提供M和E,所以还要把这两个值提取出来


1
2
3
4
5
6
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xmlString);
RSAParameters rsap = rsa.ExportParameters(false);
//下面就是需要的两个值
//rsap.Exponent
//rsap.Modulus


  如果嫌每次载入费事,可以这样(其中所有字符串常量都是从key.xml中拷贝过来的)


1
2
3
4
5
6
7
8
9
10
11
private static readonly RSAParameters rsap = new RSAParameters
{
    Modulus = Convert.FromBase64String(@"uQlRZvfH6MMdhNRgiAlKMY88dqsU2suKNIWbHY/FiTsvDgH5DLmNmGMp85qtQwSPhBQ+/E7DQkvk1OxIN7EBL+21NRPJIaDKuJciWC940ZFVU0d5oUujKy5uCrF/rfZce8MXjoiErtc+QRjCKI8wfGdIKuclooEPiJwb1rydMuE="),
    Exponent = Convert.FromBase64String(@"AQAB"),
    P = Convert.FromBase64String(@"wSwI9i+aM6h7hayvFD01iINAeZ9JK5qExBJAWDzjOQwWRE9x1dCX52jb+HrutwblfqQuOk6hazOmGTluxITXQw=="),
    Q = Convert.FromBase64String(@"9TfkbPTexGpQ9ZHNjYnmRJLcG8wG6yzzJ/RrWIjq1IKQYMhYDq08bNbUVuXlntKW9GgmEYnuhP8smrH5y+mRCw=="),
    DP = Convert.FromBase64String(@"s2Xx7LDIxLD0BnEZJ/KwhNdgSZNkoNof8vgASfJCE/jltQsS7T+L053OrDV+/PuqprJTPFNKFgUhfMuZ02iLgQ=="),
    DQ = Convert.FromBase64String(@"5IfLXXO0LI78lm/khlUPAbdwZIN3qzMABat3Y1Jur9BiZ6Au2LbASprH15h3r9WJE4wAdnX6kX4SfrUBHPW20w=="),
    InverseQ = Convert.FromBase64String(@"FhlNb2WkipUaXvuwDxEWPeE754+qM2F5otEUP9clG91yaerdsBpBmU0G6S2AqUNjr/qgfpQyl1EW2dl10rmTpw=="),
    D = Convert.FromBase64String(@"WjhPXv/Qks7T7UiqGppA+UIoToojPH1C0VIVrEfGHp/jVRakKs6sWhF7yoHwGf22xkUi4t26efBMTn84xSLCexjQwj5AQtYk+3Qr2QjRDdn2ooIV1gWKW/C0O0+80Y6PEeszItuBVfjKC6mNEcZ1g44/wOdvIG7Olsl0F7vmQrM=")
};


  将E和M传递给浏览器的方式,最直接就是写在HTML里,我个人比较喜欢把一些小数据写在<HEAD>标签的属性中,就像这样:<HEAD M="..." E="...">。C#代码也很简单:


1
2
Header.Attributes["M"] = rsap.Modulus.HexEncode();
Header.Attributes["E"] = rsap.Exponent.HexEncode();


  这里用到了一个byte[]的扩展方法HexEncode,即将byte[]转换为16进制字符串的方法,它最简单(但不一定是最快)的实现方法是


1
2
3
4
public static string HexEncode(this byte[] me)
{
    return BitConverter.ToString(me).Replace("-"string.Empty);
}


  现在是浏览器端的加密过程,引入需要的JS文件先:


1
2
3
4
<script type="text/javascript" src="js/BigInt.js"></script>
<script type="text/javascript" src="js/Barrett.js"></script>
<script type="text/javascript" src="js/RSA.js"></script>
<script type="text/javascript" src="js/jquery-2.1.0.js"></script>


  然后在加密密码之前当然要先得到RSAKeyPair对象,这个对象的构造函数定义在RSA.js中。不过在new RSAKeyPair之前,必须先调用setMaxDigits()函数,原因在BigInt.js中有说明,setMaxDigits()的参数值根据选用的RSA的Key大小不同,如果计算我不太清楚,不过按ohdave.com的示例(下载页面的源码就是示例),1024位的Key,应该设置setMaxDigits(130);如果是2048位的则应该设置为260。所以产生RSAKeyPair对象的代码应该是这样:


1
2
3
4
5
6
7
8
9
10
$(function() {
    var key = (function() {
        var m = $("head").attr("M");
        var e = $("head").attr("E");
        setMaxDigits(130);
        // 第一个参数是加密因子,第二个参数是解密因子
        // 因为浏览器端不需要解密,所以第二个参数传入空字符串
        return new RSAKeyPair(e, "", m);
    })();
})


  在提交数据之前对密码进行加密


1
var encryptedPass = encryptedString(key, $("#password").val());


  提交到后台之后,C#解密的过程


1
2
3
4
5
6
7
string hex = Request["encrypted_pass"]
byte[] data = hex.HexDecode();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
// 前面定义的private static readonly RSAParameter rsap = ...
rsa.ImportParameters(rsap);
byte[] source = rsa.Decrypt(data, false);
string password = Encodnig.ASCII.GetString(source);


  密码原文得到,剩下的事情就好说了,当然是保存密码,记得先使用HMAC算法加密哦。后面有示例下载,不是很明显,仔细找找。



本文转自边城__ 51CTO博客,原文链接:http://blog.51cto.com/jamesfancy/1361925,如需转载请自行联系原作者
相关文章
|
1天前
|
前端开发 搜索推荐 JavaScript
服务端渲染(SSR):提升现代Web应用的性能与用户体验
在现代Web应用开发中,服务端渲染(Server-Side Rendering, SSR)已经成为提高性能、SEO友好以及增强用户体验的关键技术之一。本博客将深入探讨服务端渲染的核心概念、实施方法以及为什么它对于构建现代Web应用如此重要。
|
1天前
|
前端开发 JavaScript API
前端路由:构建现代Web应用的导航之道
在构建现代Web应用程序时,前端路由是不可或缺的一部分。它允许用户在应用内导航,同时保持URL的同步,使应用看起来像一个多页面应用程序。本博客将深入研究前端路由的核心概念、实现方式、最佳实践以及如何为您的Web应用程序创建流畅的导航体验。
|
1天前
|
存储 JavaScript 前端开发
Vue.js中的组件通信:构建交互式Web应用的关键
Vue.js是一款流行的JavaScript框架,以其组件化的开发方式而闻名,但在构建复杂的Web应用时,组件之间的通信变得至关重要。在本博客中,我们将深入探讨Vue.js中的组件通信的不同方式、用法示例以及如何选择适当的通信方式来构建交互式和高效的Web应用。
|
1天前
|
数据库 数据安全/隐私保护 UED
表单处理(Form Handling):构建用户互动的Web应用的关键技巧
在Web应用程序开发中,表单是与用户互动最频繁的一种元素之一。而表单处理是使用户能够输入、提交和处理数据的关键技术。在本博客中,我们将深入探讨表单处理的概念、不同类型的表单元素、表单验证、表单提交和最佳实践,以及如何有效地使用表单处理来构建具有强大用户互动性的Web应用。
|
1天前
|
缓存 JavaScript 前端开发
列表渲染(List Rendering):构建动态Web应用的关键技术
在现代Web应用开发中,动态显示数据是至关重要的,而列表渲染是实现这一目标的关键技术之一。它允许开发者有效地渲染和管理动态生成的列表,如新闻文章、产品列表、评论等。在本博客中,我们将深入探讨列表渲染的概念、不同的列表渲染方法、性能优化以及如何利用列表渲染来构建具有动态性和响应性的Web应用。
|
1天前
|
JavaScript 前端开发 UED
事件处理(Event Handling):构建交互性Web应用的基石
在现代Web应用开发中,交互性是吸引用户的重要因素之一。而事件处理是实现这种交互性的关键。通过响应用户的操作,您可以创造出令人愉悦的用户体验。在本博客中,我们将深入探讨事件处理的概念、不同类型的事件、事件绑定、事件冒泡以及如何有效地使用事件处理来构建交互性强大的Web应用。
|
1天前
|
前端开发 JavaScript 网络架构
路由(Routing):构建现代Web应用的导航之道
在现代Web应用开发中,导航是至关重要的,用户需要能够浏览不同的页面和视图。而路由(Routing)是实现这种导航的关键概念,它允许开发人员在Web应用中定义不同的页面、视图和URL。在本博客中,我们将深入研究路由的概念、类型、工作原理,以及如何有效地使用路由来构建现代、多页面的Web应用。
|
2天前
|
人工智能 Serverless
课时8:典型案例1:一键迁移 Web 应用
典型案例1:一键迁移 Web 应用
49 0
|
XML 存储 JSON
JSON Web Token (JWT),服务端信息传输安全解决方案。
JWT介绍 JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑独立的基于JSON对象在各方之间安全地传输信息的方式。这些信息可以被验证和信任,因为它是数字签名的。JWTs可以使用一个密钥(HMAC算法),或使用RSA的公钥/私钥密钥对对信息进行签名。 让我们进一步解释这个定义的一些概念。
440 0
JSON Web Token (JWT),服务端信息传输安全解决方案。
|
缓存 JavaScript 前端开发
如何从请求、传输、渲染3个方面提升Web前端性能
从请求、传输、渲染三部分浅析如何提升web前端性能。
相关产品
云迁移中心
推荐文章
更多