一个网站要保证安全,加密、防篡改、身份识别等是起码的要求。
有几个问题:
- https 为什么公网一定要用https ?
- https 什么原理?
- https 为什么要用对称加密+非对称加密?
- https 会让请求变慢吗?
- 为什么不能只用非对称加密?
- 为什么需要数字证书?
- 有了https ,能做到加密,防篡改,身份识别吗?
- 怎么做鉴权?…
首先, 为什么要用https,纯http,用tcpdump,wirehsark 等软件抓包,根据http 协议规范,可以很简单看清每个数据包,也可以很轻松的篡改数据,动态型网站这是非常危险的。因此对传输数据加密是非常有必要的,于是有了https。
https 什么原理?
可以参考一个链接看下对称加密和非对称加密加密解密的压测分析:https://blog.csdn.net/wowotuo/article/details/80295586 。 结论是对称加密远快于非对称加密,而非对称加密非常慢。那https 如果采用纯非对称加密,如果包太大,就难以接受了。那https 能不能利用非对称加密的安全性,用利用对称加密的速度?这是可以的, https 的原理到底是怎样呢?参考图:
- 服务端非对称加密的公钥A、私钥A’。
- 客户端发起请求,服务端返回公钥A明文给传客户端。
- 客户端随机生成一个用于对称加密的密钥X,用公钥A加密后传给服务端。
- 服务端拿到后用私钥A’解密得到密钥X,保存后将sessionId 返回客户端。
- 这样双方就都拥有密钥X了,且别人无法知道它。之后双方所有数据都用密钥X加密解密。
理解了https 的原理可以知道,并不是每个body 都在用非对称加密算法加解密,而是用的对称加密算法在加密解密(部分浏览器会存在一个文件中,可以用于抓包),然后对称加密解密很快,速度比纯http 慢一点,但是并不会慢多少。
为什么要有数字证书?
服务端给客户端给公钥,并不是直接给公钥,而是给的证书,这是为什么?因为公钥可能被中间人篡改,所以为了公钥可信,证书会有公钥和私钥对公钥hash加密后一个数字签名,服务端拿着公钥对数字签名解密,如果和公钥hash 对的上,就说明公钥可靠。具体参考,https://zhuanlan.zhihu.com/p/43789231
如何鉴权?
https 能身份识别吗?其实只能做到单向识别,想鉴权,其实不够,我们还需要其他方式。常见的鉴权方式有哪些?
类md5鉴权
客户端和服务端使用同样的签名方式,服务器对请求算的结果和客户端传递的值进行对比,就可以鉴权。这里access key 用作识别用户,secret key 是盐,也可以理解成密码。这里很多开放云平台都是采用类似的加密算法,比如腾讯云采用的TC3-HMAC-SHA256 签名方法,参考链接:https://cloud.tencent.com/document/product/862/37573 。
最简单的验签方式是使用md5做单向加密:md5(msg),但是这种粗暴的加密方式的缺点就是可以暴力破解。然后升级的做法就是加盐,原理如下:
import hmac
message = 'messege' #和url,时间戳等固定参数有关
key = 'sdfsdfwfahesdfsdfsdfgwgdfgd' # 随机字符串
h = hmac.new(key, message, digestmod='MD5')
sign = h.hexdigest()
客户端和服务器约定使用相同的随机字符串作为salt ,这样,sign传递到server 后,server 使用相同的算法对提取的参数做相同运算,即可获得sign, 作为对比即可知道是否鉴权通过。我们常用的secret key 一般就是salt 。我们能对接口鉴权了后,有个问题,当不同客户有不同权限时,server 怎么识别不同的客户?这里access key 就起作用了,server 维护个字典,每个access key 对应一个 secret key , 就可以区分开客户。
server 原理类似:
dict = {
access_key1 : secrect_key1,
access_key2 : secrect_key2
} #按客户维度维护的字典,和session的性质类似
import hmac
access_key = req.header.get(access_key)
key = dict[access_key]
message = req.body.get(msg)
h = hmac.new(key, message, digestmod='MD5') #为增加复杂度,这里,会对message 混杂时间戳,uri等固定参数
sign = h.hexdigest()
if sign == req.header.get('sign'):
return true
else:
return false
rsa鉴权
还有可以利用rsa 进行签名,用对方公钥加密,传给对方,对方用自己的公钥加密,自己用自己的私钥对对方传来数据进行解密。这种方式在body 很大的时候有缺点,因为非对称加解密会很慢,优点是相对安全,据了解,有部分大厂会使用这种方式。
其实,是不是可以借鉴https ,用一种非对称+对称加密的方式鉴权。目前用第一种类md5 方式更多。