小白瞎扯常用加密算法及应用场景之MD5

前言

本文主要是个人在开始接触这块之后的一个感悟,不会对实际算法的原理以及代码做说明;只是了解各个算法的使用场景,以及解决某些问题的思路

算法类型

  • MD5
  • AES
  • RSA
  • BASE64

MD5

特点

MD5算法最大的特点就是不可逆,所谓不可逆就是用MD5加密后的数据是没有一个系统的方法去解密的;而我们常见的网上说的MD5解密,也只是相当于说一些简单的MD5加密后的数据大致被收集起来称为一个字典库一样的概念而已;如果自己加密后的数据正好被收集在其中,就会被破解;当然我们可以采用加盐值的形式来讲加密后的数据复杂化,这样更不容易破解;所谓加盐,就是在原始加密数据的后面加入另一串字符串,然后将他们放在一起进行加密;伪代码类似MD5(原内容+盐值).盐值的字符串的值看系统个人设计,随便用什么;

应用场景
1. 密码加密

比如我们在保存用户注册密码的时候,为了防止密码的明文传输,可以将密码使用MD5加密之后传入到服务器,然后服务端保存将加密后的数据保存到数据库中;事实上可以先由客户端对原始密码进行加密后传输到服务端,服务端也进行加密。由于MD5不可逆,事实上连系统都无法获取用户的密码;然后当我们验证用户输入的时候,同样使用加密后的密码来与数据库进行匹配;当然为了加密的复杂性,我们可以加入盐值,这个盐值可以由服务端传送给客户端,也可以双方约定好一个规则;
最简单的伪代码

// ========================================客户端===================================
// 1. 接收用户输入
var password = input('password').val()
// 2. 对密码进行md5加密,我们可以设计一个盐值,这个盐值必须不能变动,否则就会和数据库不一致了
var encrypt = MD5(password + '我是密码专用盐值')

// ========================================服务端===================================
// 1. 获取客户端已经加密一次的密码
String password = getPassword();
// 2. 使用相同算法(也可以不相同)再对加密后的密码再来一次MD5
password = MD5(password + '我是密码专用盐值');
// 3. 保存到数据库
insert(password);

// 登录逻辑
// 客户端以及服务端1-3和注册时保持一致
// 4. 对再加密后的密码和数据库中进行匹配
select * from user where username=? and password = ${password}
2. 验证文件完整性

这个就用的也是比较多的,我们经常从网上下载资源,一般资源后面都会提供一个MD5码,这个的作用就是,文件提供者,会预先获得文件的MD5码,然后当别人把文件下载下来之后,可以获取自己下载这个文件的MD5码与服务端提供的相对比,由于MD5不可逆且内容中的更改会导致MD5码的变化,那么我们自然就能通过MD5的比较来确定下载的这个文件是不是就是和服务端提供的文件是同一个文件;

3. 接口数据加签

注意我们说的是加签,而不是加密;加签和加密是两个完全不同的问题;加签主要是为了验证数据的完整性,是否被篡改;加密是用来解决数据传输过程中关键信息的不可人为读,只有接收方解密之后才能看到真正的数据。由于接口传输的数据是需要可逆解密的,所以不能使用MD5作为加密手段;这个后面会讲解。
这也是一个很常用的使用场景,通常在接口设计中,由于接口需要接收外部数据,然后做业务处理;那么接口能保证自己接收的数据是正常的数据,就是别人传送过来的,就是非常重要的事情了;比如我们的接口接收要付款的金额,客户端明明传的是100,但是这个值被劫持之后然后改成了10000,而服务端直接去处理10000,就会造成非常严重的后果;那么如何使用MD5来解决这个问题呢?

其实这是一个很复杂的问题,场景不同会有很多概念牵扯到里面;我们这里不考虑复杂的情况,只考虑当前的MD5的问题;
由于MD5的不可逆性,那么我们是不是可以在原始的参数中加入一个原始数据加密后的值呢?由客户端对要传送的数据进行加密,然后将这个加密后的字符串也传送给服务器;服务端接收到客户端的参数之后,也对参数做MD5加密(要排除传加密后的这个参数),如果加密后的值与参数的值相同,那么就能够确定当前接口中的数据没有被修改;

当然这种思路还是有一个问题,就是劫持方,对参数中的数据修改了之后,同时对新的参数进行加密,然后将新的加密串覆盖原始的加密串,服务端接收到之后其实是无法判断参数是有没有修改的;这个时候我们前面说的盐值的作用就体现出来了;比如我们约定了一个盐值的规则(也可以由服务端提供给客户端,但是一定不能泄露,其实也可以成为加密秘钥)。这样客户端在进行加密的时候加入盐值,由于别人无法知道我们的盐值,所以他加密的算法和我们是不一样的,一旦他修改数据,服务端就会立马识别到MD5加密串的区别,从而放弃本次接口处理;
大致伪代码体现如下,比如我们的请求参数是key1=value1&key2=value2,我们约定好的秘钥是woshiyigemiyao,秘钥是约定的一个字符串,规则自定,没什么要求的。

// ========================================数据发送方========================================================
// 1. 客户端对参数和秘钥进行加密,当然秘钥前也可以固定给一些参数比如key=woshiyigemiyao
String sign = MD5("key1=value1&key2=value2" + "woshiyigemiyao");
// 2. 然后客户端将原始参数传送给服务端的同时将上面的加密串也传送给服务端,我们约定传送加密串的参数叫sign
send_to_server("key1=value1&key2=value2&sign=" + sign);


// =========================================数据接收方========================================================
// 1. 服务端接收到客户端请求,先对除sign以外的参数进行和客户端一样的加密方式,参数顺序必须一致
String encrypt = MD5("key1=value1&key2=value2" + "woshiyigemiyao");
// 2. 获取客户端传送的加密串
String sign = getParam("sign");
// 3. 和自己接收到的参数加密后的MD5进行比较,如果相同则验证通过,证明内容没有被修改
if (!encrypt.equals(sign)) {
	// 放弃本次接口请求
	return;
}
// continue do something
总结
  • 对于伪代码里的加密接口请求的参数,其实还可以加入一些参数来提供安全性,比如加入当前的时间戳,具体到分钟即可;然后服务端也将时间戳加入加密参数中。这样也能在一定程度上保证有些数据即使被别人保留下来,然后重发,但是时间已经过期,服务端也不会处理;
  • 会有一些地方会说明在进行上述加密前,先对参数进行排序;这么做的原因是因为即使是参数的值没有修改,但是如果服务端和客户端对参数加密使所放置的位置不一致时,也会导致最终的加密串不一致;关于这一块我觉得可能约定大于排序吧,看个人选择;最好在传参时就约定了,必须按照给定的顺序来传参
  • 可以参考微信的签名算法说明;比上述的更详细一些;https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3
  • 可以看到MD5并不能用来作为数据加密传输时使用,由于它的不可逆,接收方无法解密,所以加签时可以使用,但是加签虽然能够阻止数据被修改却没有解决数据加密的问题;加密和加签是用来解决两个安全不同的问题的,这就牵扯到对称加密与非对称加密。后面会作一个粗略的入门讲解;
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值