在网络传递数据的时候,为了防止数据被篡改,我们会选择对数据进行加密,数据加密分为对称加密和非对称加密。其中RSA和AES,TLS等加密算法是比较常用的。
对称加密
对称加密是指加密和解密使用相同的密钥的加密方法。其基本流程包括以下步骤
- 密钥生成:双方协商生成一个共享密钥或由一方生成密钥并安全地传输给另一方。
- 加密:使用共享密钥对原始数据进行加密,得到加密后的数据。
- 传输:将加密后的数据传输给另一方。
- 解密:接收方使用相同的共享密钥对加密数据进行解密,得到原始数据。
非对称加密
非对称加密是指加密和解密使用不同的密钥的加密方法,通常称为公钥和私钥。其基本流程包括以下步骤:
- 密钥对生成:生成一对密钥,一个是公钥,另一个是私钥。公钥可以公开,而私钥需要保密。
- 公钥分发:将公钥发送给需要加密数据的一方。
- 加密:使用公钥对原始数据进行加密,得到加密后的数据。
- 传输:将加密后的数据传输给另一方。
- 解密:接收方使用私钥对加密数据进行解密,得到原始数据。
结合使用:
在实际应用中,对称加密和非对称加密通常会结合使用以达到安全和效率的平衡。例如:
- 使用非对称加密交换对称密钥。
- 使用对称密钥进行数据加密和解密。
什么是数字签名
再上面我们了解了RSA对称加密,那么当我们进行数据交换的时候,如下:
假设有AB两个人,假设前面他们已经交换完毕了公钥。
那么此时当A使用B的公钥加密原始数据然后发送数据给B的时候,它可以再数据的后面再携带上一个原始数据hash计算之后得到的hash值,然后用自己的私钥进行加密。
A将数据发送到B之后,由于数据使用的是B的公钥加密,B可以用私钥解密之后,得到A发送消息的原本内容,然后,B可以使用A的公钥对额外的数字签名进行校验,因为它假设这个数据是A发送的,那么用A的公钥就应该可以解密成功,所以如果数据解密成功之后与A发送的原始消息经过一样的Hash运算之后相等,那么说明没有被篡改,而如果不一致,那么就说明被篡改了。因为第三方是不知道A的私钥信息的,所以他是用自己的私钥去加密,得到的hash会与A进行hash之后的值不同,从而判断数据被篡改了。关注公众号:码猿技术专栏,回复关键词:1111 获取阿里内部Java性能调优手册!
HTTPS与CA
https其实不是一个单独的协议,而是数据传输的时候使用TLS/SSL进行了加密而已。而TLS就是一个非常典型的非对称加密,其兼顾了AES和RSA的安全性和速度。
上面我们已经聊完了一个加密数据的交换过程,那么如果有些人就是伪造了一些域名让你去访问怎么办呢?
HTTPS (HTTP Secure) 是一个安全的 HTTP 通道,它通过 SSL/TLS 协议来保证数据的安全传输。在 HTTPS 请求的过程中,证书颁发机构 (CA, Certificate Authority) 扮演了重要的角色。以下是 CA 在保证 HTTPS 请求过程中数据安全交换的方式:
- 证书颁发:CA 为服务器颁发一个数字证书。这个证书包含了服务器的公钥和一些识别服务器身份的信息。数字证书是由 CA 签名的,以验证证书的真实性和完整性。
- 建立安全连接:当客户端第一次连接到服务器时,服务器会发送其数字证书给客户端。客户端会验证数字证书的合法性,比如检查证书是否由一个受信任的 CA 签名,检查证书是否在有效期内等。一旦证书验证通过,客户端就能确认它是与正确的服务器进行通信,而不是被中间人攻击。
- 密钥交换:客户端和服务器会使用 SSL/TLS 协议中的密钥交换机制来协商一个会话密钥(通常是一个对称密钥)。一种常见的方法是客户端生成一个随机的对称密钥,然后用服务器的公钥加密它,再发送给服务器。服务器用自己的私钥解密得到对称密钥。
- 数据加密和传输:一旦会话密钥被协商好,客户端和服务器就会用这个密钥来加密和解密传输的数据。这样,即使数据在传输过程中被截获,攻击者也无法解读数据的内容,因为他们没有会话密钥。
- 完整性校验:SSL/TLS 协议还提供了数据完整性校验。它会为传输的数据生成一个 MAC (Message Authentication Code),以确保数据在传输过程中没有被篡改。
图片
其实前面的第一和第二随机数都是正常传输,预主密钥的得到就是使用RSA了,此时只有客户端和服务端知道预主密钥,之后,对第一和第二随机数使用预主密钥的加密,就可以得到会话密钥,此时加密交互完成。
并且会话密钥只应用在当前会话,每个会话都会新生成一个,所以安全性大大增加。
只有前面的得到预主密钥的过程用RSA,其他地方都是AES,因为,非对称实在太慢了。
Gateway网关的过滤器链
我们知道,我们可以再Gateway网关中自定义过滤器,并且实现Ordered接口来对过滤器的执行顺序进行排序。如下图我实现了三个自定义的全局过滤器。
图片
并且,当你实现全局过滤器接口的时候,你必须实现如下方法
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain)
其中exchange参数非常重要,他就是你的请求以及对你请求的响应。而chain就是上面的过滤器链条。
图片
而我们的过滤器链的作用,其实就是对request和response这两个重要的类进行操作。
比如我可以使用exchange.mutate方法来对request和response进行修改。
如下是我修改request之前的请求体内容。
图片
如下就是我修改URI之后的request请求体的内容。
图片
在这里我们把这个reqeust给他修改有着重大意义,这意味着只要对加密后的数据进行解密后,去修改这个request中的内容,我们就能再一次成功的将我们的请求路由到我们指定的路径。
图片
而之后,我们最终路由到的请求路径位置,保存在了DefaultServerWebExchange的attributes中。
![ttps://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a9bf57e6a521475fb8e403526290533e~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp#?w=1766&h=1273&s=401141&e=png&b=f9f5f5)
最后只要进入到ForwardRoutingFilter
图片
在这里请求完成了最终的处理,然后进行转发,发送到对应的处理类去处理。
这时候我们看提供远程服务调用的类的调用栈即可。
图片
如何对自己的路径传输设定一个数字签名?
上面我们已经聊到了,先使用RSA的方式传递对称密钥,然后之后的请求使用AES来进行加密解密。这样子既保证了安全性也保证了请求的速度。
我就按照上面的说法,简单的实现了一个数字签名,大概方式如下:
前端获取RSA公钥
我们首先在gateway网关提供一个接口用于提供给前端获取RSA公钥。
图片
发送加密后对称密钥
前端使用得到的公钥对自己的对称密钥进行加密,代码如下:
后端接收当前会话对称密钥并保存
这里由于我没有前端,不好操作,我就直接暂时写死了,但是具体的实现逻辑就是与前端制定一个唯一的会话id,然后之后只要是同一个会话就可以使用同一个对称密钥,这样子才能进一步保证安全,而不是一直使用同一个对称密钥。
前端发送AES加密请求
比如这里的请求参数为productId=1,然后我们额外发送一个signature=wHYOLLkTn00DVrcmuCFzFQ==,signature的值就是对这个参数productId=1进行AES加密之后得到的数据。
然后我们再一次对String plaintext = "productId=1&signature=wHYOLLkTn00DVrcmuCFzFQ==";来进行加密,然后发送的请求以这个为参数。
也就是发送:
只要后端检测到这个路径有任何一点不对劲,就会直接报错返回。
验证请求
而如果请求的参数被篡改了,比如上面的productId=2,那么有如下图情况:
图片
此时验证请求是否被修改的方法就会报错。
图片
下面再验证请求是否被篡改的过程中,代码写的可能有一点丑陋。
如果请求的过程中,请求的数据并没有被修改,那么可以正确解析,如下:
图片
如何实现URL的动态加密?
动态加密其实在上面就已经说了。
可以发现我们发送的实际请求是下面这个,/encrypt/后面的就是我们约定好的加密参数。
实际再处理过程中会去掉/encrypt,他只是用于标识具体的加密参数位置而已。