文章目录
- 一.前言
- 二.安全措施
- 1.数据加密
- 2.数据加签
- 3.时间戳机制
- 4.AppId机制
- 5.限流机制
- 6.黑名单机制
- 7.数据合法性校验
- 三.如何实现
- 1.数据加密
- 2.数据加签
- 3.时间戳机制
- 4.AppId机制
- 5.限流机制
- 6.黑名单机制
- 7.数据合法性校验
- 四.源码
一.前言
相关术语
- 加密:encryption
- 解密:decryption
- 秘钥:secret key (公钥:public key 私钥:private key)
- 数字签名:digital signature
- 数字证书:digital certificate
- 摘要:digest
个人觉得安全措施大体来看主要在2个方面
- 是如何保证
数据在传输过程中不被窃取
- 是数据已经到达服务器端,
服务器端验证传过来的数据没有被篡改,如何不被攻击
二.安全措施
1.数据加密
我们知道数据在传输过程中是很容易被抓包
的,如果直接传输比如通过http协议
,那么用户传输的数据可以被任何人获取,所以必须对数据加密。常见的做法对关键字段加密,比如:用户密码直接通过md5加密。加密的作用是保证数据在传输过程中不被窃取。
- 现在主流的做法是使用
https协议
,在http和tcp之间添加一层加密层(SSL层)
,这一层负责数据的加密和解密;
2.数据加签
数据加签就是由发送者生成一段无法伪造的一段字符串,来保证数据在传输过程中没有被被抓包篡改。
你可能会问数据如果已经通过https
加密了,还有必要进行加签吗?
- 数据在传输过程中经过加密,理论上就算被抓包,也无法对数据进行篡改;但是我们要知道加密的部分其实只是在
外网
,现在很多服务在内网
中都需要经过很多服务跳转,所以这里的加签可以防止内网中数据被篡改
。
3.时间戳机制
数据是很容易被抓包的,但是经过如上的加密
,加签
处理,就算拿到数据也不能看到真实的数据。但是有不法者不关心真实的数据,而是直接拿到抓取的数据包进行恶意请求
。这时候可以使用时间戳机制
- 在每次请求中加入当前的时间,服务器端会拿到
当前时间和请求中的时间相减,看看是否在一个固定的时间范围内
,比如5分钟内。这样恶意请求的数据包是无法更改里面时间的,所以5分钟后就视为非法请求了。
4.AppId机制
大部分网站基本都需要用户名和密码才能登录,并不是谁来能使用我的网站,这其实也是一种安全机制。对应的对外提供的接口其实也需要这么一种机制,并不是谁都可以调用,需要使用接口的用户需要在后台开通appid
,提供给用户相关的密钥
(appSecret)。在调用的接口中需要提供appid以及密钥(主要用于与生成签名sign),服务器端会进行相关的验证;
5.限流机制
本来就是真实的用户,并且开通了appid,但是出现频繁调用接口
的情况;这种情况需要给相关appid限流处理
- 常用的限流算法有
令牌桶
和漏桶算法
。
6.黑名单机制
如果此appid进行过很多非法操作,或者说专门有一个中黑系统
,经过分析之后直接将此appid列入黑名单
,所有请求直接返回错误码
.
7.数据合法性校验
这个可以说是每个系统都会有的处理机制,只有在数据是合法的情况下才会进行数据处理
。每个系统都有自己的验证规则,当然也可能有一些常规性的规则,比如身份证长度和组成,电话号码长度和组成等等;
三.如何实现
以上大体介绍了一下常用的一些接口安全措施,当然可能还有其他我不知道的方式,希望大家补充,下面看看以上这些方法措施,具体如何实现;
1.数据加密
现在主流的加密方式有对称加密(单钥加密)
和非对称加密(双钥加密)
。
- 对称加密:对称密钥的
加密
和解密
中使用的密钥是相同的
- 常见的对称加密算法有:
DES
,AES
- DES:
比较老的算法
,一共有三个参数入口(原文,密钥,加密模式)。而3DES只是DES的一种模式,是以DES为基础更安全的变形,对数据进行了三次加密,也是被指定为AES的过渡算法
。
-AES:高级加密标准,新一代标准,加密速度更快,安全性更高(优先选择)
- 优点:
计算速度快
,适合对大数据进行加解密。 - 缺点:是在数据传送前,
发送方和接收方必须商定好密钥
,然后使双方都能保存好秘钥,如果一方的秘钥被泄露,那么加密信息也就不安全了
。
密钥只有一把,所以密钥的保存变得很重要。一旦密钥泄漏,密码也就被破解。
由于对称加密加解密速度快,因此可以和非对称加密混合使用,可以使用非对称加密方式加密对称加密的密钥,来保护密钥的安全。
- 非对称加密:
加密和解密使用不同的密钥
,由服务端
会生成一对密钥
,私钥
存放在服务端
,公钥
可以发布给任何人
使用。用公钥加密的数据,只能用和它对应的私钥解密,用私钥加密也只能同与之对应的公钥解密。
- 常见的非对称加密是
RSA 加密
算法 - 优点: 比起对称加密更加安全
- 缺点: 加解密的速度比对称加密
慢
太多了(如:密钥对的生成,根据公钥反推私钥) 不适合对大数据进行加解密 - 场景: 最常用的使用场景就是
数字签名
和密码传输
,用作数字签名
时使用私钥加密,公钥解密;用作加密解密
时,使用公钥加密,私钥解密。
同时生成公钥和私钥应该相对比较容易,但是从公钥推算出私钥,应该是很困难或者是不可能的
- 两种方式各有优缺点,而
https
的实现方式正好是结合了两种加密方式
,整合了双方的优点
,在安全和性能方面都比较好
对称加密和非对称加密代码实现,Java提供了相关的工具类可以直接使用,此处不过多介绍,关于https如何配置使用相对来说复杂一些 HTTPS分析与实战
2.数据加签
3种数据签名安全策略:消息摘要
, 数字签名
, 数字签名+加密[证书]
安全策略 | 描述 | 安全级别 |
消息摘要(Digest),也称消息Hash | 将数据和Key(自定义密钥)组合后进行hash |
|
数字签名(Signature) | 使用证书和非对称签名算法对数据进行签名 |
|
签名-加密[证书] | 使用证书和非对称算法对数据签名,使用一次一密的密钥和对称算法对数据进行加密 |
|
- 机密性(Confidentiality): 未经许可不许看
- 完整性(Integrity) : 不许篡改
- 可用性(Availability) : 防止不可用
- 不可抵赖性(Non-Repudiation): 用户不能否认其行为
1.消息摘要(Digest)
- 消息摘要使用比较多的摘要算法(也称Hash算法)是有
MD5、SHA-1、SHA-256
,将需要提交的数据通过某种方式组合成一个字符串,然后通过hash算法生成一段加密字符串,这段字符串就是数据包的签名signature
。,比如:
这个固定长度的 Hash 值,就是这份数据的摘要,也称为指纹。
str = 参数1={参数1}&参数2={参数2}&……&参数n={参数n}&signature={用户密钥};
MD5.encrypt(str);
注意:最后的用户密钥signature
,客户端和服务端都有一份
,这样会更加安全;
- 消息摘要原理:
Hash算法不可逆
,并且计算结果具有唯一性
,在用户密钥
的隐私得到保证的情况下,可以保证完整性 - 消息摘要缺陷:
用户密钥
的是明文传输
的,隐私性很难保证。
2.数字签名(Signature)
如果用「公钥」对数据加密,用「私钥」去解密,这是「加密」
; 反之用「私钥」对数据加密
,用「公钥」去解密
,这是「签名」
!!!
简单地看,似乎没有区别,只是换了个名字。但实际上,两者的用途完全不一样。 因为
所有人都持有公钥,所以「签名」并不能保证数据的安全性
,因为所有人都可以用公钥去解密。 但「签名」却能用于保证数据的准确性和不可否认性
。因为公钥和私钥是一一对应的
,所以当一个公钥能解密某个密文时,说明这个密文一定来自于私钥持有者。
高效的数字签名方案: 将摘要算法(Hash算法)
和非对称加密结合
使用。
-
如何签名
:客户端先用Hash算法
计算明文数据
的Hash值
,再对这个Hash值用 “私钥“ 加密
。这样就能较快速地得到了原始信息的签名
,将明文数据以及密文同时传给服务端 -
如何验证
:服务端先用相同的Hash算法
计算客户端传递明文数据的Hash值
,再用“公钥“ 对 客户端传递的签名进行解密
,得到收到的Hash值,最后对比这两个Hash值判断是否相等。如果不相等说明数据不可信。
如果明文数据特别庞大,直接使用非对称加密生成签名会导致加解密的效率特别底下(慢慢慢),这也是为什么上面会
先将明文数据hash后在通过私钥加密
具体操作
- 客户端 对
明文数据
做一个md5/SHA
计算,对计算后的值通过 "私钥" 加密得到密文(签名)
,客户端 将明文数据
和密文
发送给服务端 - 服务端 对
密文
通过“公钥解密”
得到值A
,同时 服务端 对明文
做一个md5/SHA
计算得到值B
- 服务端比较客户端与服务Hash的明文值A与值B,
相同得验证通过
,如果不相等说明数据不可信。
能够保障不可篡性
和不可抵赖性
,但是不能保障数据的私密性
(明文传输)
- 即使他人截获并篡改了
「明文数据」
,由于「私钥」
是保密的,篡改者也无法生成正确的「签名」
。所以能保证数据的完整
。
3.签名+加密[证书]过程
- 客户端生成一个
随机字符串
,作为password
,然后把这个password通过B公钥加密生成密文C
,把A明文通过password加密生成密文B
, - 同时把
A明文
做MD5/SHA
计算后的值通过A私钥
加密得到签名D
, 把密文B
和密文C
和签名D
发给服务端,服务端通过私钥解密文C得到password
,然后通过password解密文B
就可以得到A明文
,同时签名
可以用来验证发送者是不是A
,以及A发送的数据有没有被第三方修改过
。
假设存在一个恶意的一方X,冒充了A,发送了密文B(password生成)
,密文C
,服务端收到数据后,仍然可以正常解密得到明文,但是却无法证明这个明文数据是A发送的还是恶意用户B发送的
。签名D
的含义就是A自己签名
,服务端可以验证。X
由于没有A的私钥
,这个签名它无法冒充,会被服务端识别出来。
3.时间戳机制
解密后
的数据,经过签名认证
后,我们拿到数据包中的客户端时间戳字段
,然后用服务器当前时间去减客户端时间,看本次请求是否超时
。
伪代码如下:
long interval=5*60*1000;//超时时间
long clientTime=request.getparameter("clientTime");
long serverTime=System.currentTimeMillis();
if(serverTime-clientTime>interval){
return new Response("超过处理时长")
}
4.AppId机制
生成一个唯一的appId以及对应的appSecret(密钥)。密钥使用字母、数字等特殊字符随机生成即可;
- 生成唯一appId根据实际情况看
是否需要全局唯一
,但是不管是否全局唯一最好让生成的Id有如下属性:
- 趋势递增:这样在保存数据库的时候,使用索引性能更好。
- 信息安全:尽量不要连续的,容易发现规律。
- 关于
全局唯一Id
生成的方式常见的有类Snowflake
(Snowflake 俗称雪花算法,用于生成分布式自增 ID
)方式等;
5.限流机制
常用的限流算法包括:固定窗口计数器算法
、滑动窗口计数器算法
、漏桶限流
,令牌桶限流
,
计数器限流:”计数器是一种比较简单粗暴的算法,主要用来限制总并发数,比如数据库连接池、线程池、秒杀的并发数;计数器限流只要一定时间内的总请求数超过设定的阀值则进行限流;
- 固定窗口计数器算法
规定我们单位时间处理的请求数量。比如我们规定我们的一个接口一分钟只能访问 10 次的话。使用固定窗口计数器算法的话可以这样实现:
- 给定一个变量 counter 来记录处理的请求数量,当 1 分钟之内处理一个请求之后 counter+1,1 分钟之内的如果 counter=100 的话,后续的请求就会被全部拒绝。等到 1 分钟结束后,将 counter 回归成 0,重新开始计数(ps:只要过了一个周期就讲 counter 回归成 0)。
- 这种限流算法无法保证限流速率,因而无法保证突然激增的流量。比如我们限制一个接口一分钟只能访问 10 次的话,前半分钟一个请求没有接收,后半分钟接收了 10 个请求。
- 滑动窗口计数器算法
算的上是固定窗口计数器算法的升级版。滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:
- 它把时间以一定比例分片,比如一分钟分为 6 个区间,每个区间为 10s。每过一定区间的时间,就抛弃最前面的一个区间,如下图所示。如果当前窗口的请求数量超过了限制数量的话,就拒绝后续请求。
很显然:当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。
- 漏桶限流
漏桶算法的原理是按照固定常量速率流出请求,流入请求速率任意,当请求数超过桶的容量时,新的请求等待或者拒绝服务;可以看出漏桶算法可以强制限制数据的传输速度;
- 个人理解: 我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。如果想要实现这个算法的话也很简单,准备一个队列用来保存请求,然后我们定期从队列中拿请求来执行就好了。
- 令牌桶限流
令牌桶算法的原理是系统以一定速率向桶中放入令牌,填满了就丢弃令牌;请求来时会先从桶中取出令牌,如果能取到令牌,则可以继续完成请求,否则等待或者拒绝服务;令牌桶允许一定程度突发流量,只要有令牌就可以处理,支持一次拿多个令牌;
- 个人理解: 令牌桶算法也比较简单。和漏桶算法算法一样,我们的主角还是桶(这限流算法和桶过不去啊)。不过现在桶里装的是令牌了,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。我们根据限流大小,按照一定的速率往桶里添加令牌。
具体基于以上算法如何实现,Guava
提供了RateLimiter工具类
基于基于令牌桶算法
:
RateLimiter rateLimiter = RateLimiter.create(5);
- 以上代码表示一秒钟只允许处理五个并发请求,以上方式只能用在
单应用
的请求限流,不能进行全局限流
。这个时候就需要分布式限流
,可以基于redis+lua
来实现;
6.黑名单机制
如何为什么中黑我们这边不讨论,我们可以给每个用户设置一个状态
比如包括:初始化状态,正常状态,中黑状态,关闭状态
等等,或者我们直接通过分布式配置中心
,直接保存黑名单列表,每次检查是否在列表中即可
7.数据合法性校验
合法性校验包括:常规性校验
以及业务校验
- 常规性校验:包括签名校验,必填校验,长度校验,类型校验,格式校验等。
- 业务校验:根据实际业务而定,比如订单金额不能小于0等。
四.源码