ToB企服应用市场:ToB评测及商务社交产业平台
标题:
接口安全设计之防篡改和防重放
[打印本页]
作者:
海哥
时间:
2024-7-22 12:21
标题:
接口安全设计之防篡改和防重放
概述
配景
之以是想跟大家分享怎么做好基础的接口安全,一方面是工作需要,之前这部分的工作是我在负责,以是正好有这部分的履历;二是我之前也接触过许多做后端的同学,对于这一块大部分涉及不深或不太相识,也不知道怎么样做才算相对安全。以是把我的想法写出来,供大家参考和讨论,共同学习和进步。
固然了,我分享的也只是我的个人履历,自然有许多的不足之处,也并不是说我后续叙述的一些观点和实现就一定是安全的,大家要加入本身的判定,并且混入一些定制化的东西
适用范围
本章节内容,主要说的HTTP接口的安全设计,涉及内容包括
防窃听、防篡改、防重放、密钥传输安全、密钥存储安全、敏感数据
处理等。适用于负责
后端、测试或信息接口安全的同学
防篡改
数据加签
为相识决这类标题,
前端可以给数据加上一个署名
,好比接纳MD5最简朴的署名方式,可以
把哀求参数看成待署名的数据
,计算一个MD5值,然后传给服务端,
服务端同样用参数生成MD5值进行比对
,发现不一样,那阐明数据被篡改过了。
数据加签的机制是没有标题的,并且确实可以解决防篡改的标题,但是算法和机制要选好。
无论是MD5、HMAC、还是别的类型的摘要算法,都有一个标题,就是篡改者要是知道了算法,那还是可以篡改。以是要
选用非对称算法来做数据的加签与验签
,如许就算篡改者知道了算法,但是
没有私钥也篡改不了
,由于
非对称的机制就是用私钥署名,公钥验签
,公钥可以公开出去。
好比客户端用客户端的私钥对哀求参数进行署名,并把公钥给到服务端,服务端在收到哀求后,
用客户端的公钥进行验签。就算篡改者知道了客户端的公钥,也无法对哀求数据进行篡改
,此时客户端的重心就转移到了,如何保护它的私钥标题上了,而不用担心数据会被别人篡改
署名是只能由私钥生成,公钥验签。公钥是无法生成署名,同时使用公钥验的。这就是非对称算法的利益。
双签(双向传输加密)
同样的,服务端把本身的公钥给到客户端,服务端在响应数据的时候,进行署名,客户端进行验签,这就是双签。即客户哀求时,使用客户端的私钥署名,服务端验,服务端响应时,使用服务端的私钥署名,客户端验。来确保数据交互时哀求和响应都不会被篡改。
常用算法
常用的算法有
RSA1024、RSA2048、SM2
,固然另有一些别的ECC类算法。早期大家用的根本是RSA1024,如今大部分都用2048或更长的密钥来生成署名了。固然也有效
国密
的,不外用的少,像我们公共交通行业用的多,另有就是国企。我如今设计体系,根本是天下密体系了,除了一些要给第三方调用的,会做RSA+SM2,就是任选其一。
SM2
有个利益就是生成的署名是
64字节
的,RSA的话,密钥越长,署名值就越长,计算复杂度也越高,体系负载固然也会跟着上去。国密应用这么多年了,安全性还是不用担心的。
接下来,我们就用国密来实现数据的加签,实战一波。
加签数据设计
GET哀求
对于GET类的哀求,我们可以将参数先按字母进行一个排序,然后把他们拼装起来,好比:
curl -v 'http://127.0.0.1:8080/testGet?p=testp&ab=123&x=456'
复制代码
那么参数排序,并拼装后变成:
ab=123&p=testp&x=456
复制代码
POST哀求
POST如果是FORMDATA形式,我们也可以像GET哀求一样,先将参数进行排序,再拼装,好比:
curl -v -H 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' --data-binary "p=test1&ab=123&x=456" 'http://127.0.0.1:8080/testPostFromdata'
复制代码
同时按照GET的参数拼装方式,拼装后变成:
ab=123&p=test1&x=456
复制代码
POST BODY
对于传输的数据是BODY形式的,我们可以约定一种拼装方式,把BODY原封不动的作为entity的值来拼接,如:
curl -v -H 'Content-Type: application/json' --data-binary '{
> "pInt": 1,
> "pBoolean": false,
> "pString": "ssss"
> }' 'http://127.0.0.1:8080/testPostBody'
复制代码
拼接后变成:
entity={"pInt": 1,"pBoolean": false,"pString": "ssss"}
复制代码
这里entity的值就是BODY的内容,原封不动,有换行也是要体现,这里为了方便大家查看,换行符我就去掉了。
标题一
有了这个规则之后呢,要署名的数据是有了,但大家有没发现一个标题,如果哀求参数是空的,咋办,没有数据可签肯定也不行。
标题二
如果两个不同的方法参数个数是一样的,参数名也一样,那是不是有了署名值,别的老六就可以作文章了。
标题解决方案
以是呀,为相识决上面的两个标题,我们可以把要哀求的接口地点也加到待署名的数据里去。好比:
curl -v 'http://127.0.0.1:8080/testGet?p=testp&ab=123&x=456'
复制代码
可以约定接口地点的键为path,并且不参与排序,直接拼在后面,那么上述哀求的待签数据是:
ab=123&p=testp&x=456
&path=/testGet
复制代码
如许是不是即解决了参数可能为空,又避免了别人用同样的参数和署名值去访问别的接口的标题。
署名值存放
关于署名值放置的位置,可以根据大家的需要,放哀求头Header里或公共参数都可以。
关于算法
关于SM2署名算法有几点跟大家提一提。
署名肯定都是私钥署名,公钥验签。
验签的复杂度比署名高,由于验签有两次点乘一次点加,而署名是一次点乘。
署名如果只有公钥的话,要多一次点乘,即从私钥生成公钥,以是服务器写署名算法,就把公私钥都生存起来,可以省掉一次点乘。
署名算法在计算z的时候,要传入userid,默认都是1234567812345678。这里如果是非标的话,可以定制和作文章,加大安全性。
署名需要随机生成大数 in [1, n - 1],不要偷懒,固然别人封装好的,一般都会处理。
集群部署
通常为满足集群部署,水平扩展的要求,我们需要把用户用于验签相干的内容缓存到内存中(好比Redis),以减少数据库这方面的查询压力。
注意事项
对于GET类的哀求,通常的参数的值可能需要
颠末encodeURI处理,这里指的是拼装待署名数据的时候
,哀求传参时不需要
对于POST类哀求,在写拦截器的时候,
要定制InputStream,由于拦截验签的时候,会先把BODY读出来,以是处理完要写回去
,或接纳别的雷同方法处理
这类非功能性需求,如果条件允许,
可以将缓存用户公钥这类服务独立出来,增长服务的可用性。
前端和后端加密的参数一定要包管每个参数的数据类型一致
,否则末了加密的结果可能不同(博主亲身踩的坑)
降级处理
针对Redis不可用的降级处理呢,我个人想法是如许的,可以事先根据用户的公钥,使用服务端的私钥生成一个证书,下发给客户端,好比证书内容为:
序号字段名字段类型长度(单位字节)备注1用户标识ANSIN用户唯一标识2证书签发时间HEX4UTC时间戳,单位秒3证书失效时间HEX4UTC时间戳,单位秒4密钥索引HEX1使用服务端的哪个私钥签发的5客户端公钥HEX33压缩SM2公钥6数字署名HEX64使用指定索引下的私钥对1-5进行署名 一旦发生Redis不可用,防篡改这块业务需要降级处理的话,就让客户端在哀求时,将证书也发过来,服务端先验证书,证书有效的情况下,用证书里的公钥验客户端署名。
这种方法呢,
会增长客户端的流量、服务端流量以及服务器的负载
防重放一
上一章节,为了
防篡改
,我们给第一个哀求
增长了署名和验签
,如许就可以解决数据防篡改标题。你以为如许就安全了吗?我们看,同一接口,同样的参数,同样的署名值,是不是每次调用,都是可以成功的。如果被恶意使用,非法用户疯狂的调用这一个接口呢,服务器资源是不是就浪费了,如果这个接口业务比较复杂,还要操纵数据库,正好操纵数据库也耗时,那是不是有可能给搞的当机了。
那有没有办法解决这个标题呢,固然有。好比再给
每一个哀求加上一个时间戳
,
并且时间戳也加入署名防篡改
,是不是可以先验证这个哀求是什么时候发起的,有没有超过指定时间(好比3分钟),超过就直接丢弃。
好比这个接口:
curl -v -H 'X-TimeStamp: 1680503150' 'http://127.0.0.1:8080/testGet?p=testp&ab=123&x=456'
复制代码
我们在Header里,多传了一个X-TimeStamp,值为距离1970-01-01的UTC秒数,
为了防止别人篡改呢,也需要将其作为署名的数据
,好比固定参数名为timestamp,放置在path后面,也不参与排序,那么待署名数据就变成了:
ab=123&p=testp&x=456
&path=/testGet×tamp=1680503150
复制代码
遗留标题
加入时间戳后,可以有效的防止重放,但有效期内哀求仍然有效,以是需要加入别的方案来增强,好比限流。又好比后续讲到的
nonce(随机串)
。
时间戳有一个客户端与服务器时间可能会不同步的标题,以是多少分钟内有效,要根据业务需要来定。另外也可以在服务器加入获取服务器当前时间的接口,来同步客户端与服务端的时间。
如果加了获取服务器时间这种无状态的接口,也要考虑加入署名及验签机制,或者限流机制,防止攻击。
防重放二
上面讲到了,为了防止接口重放,我们给
每一个哀求加上一个时间戳
,但是如许并没有完全地解决防重放标题,
有效期内还是可以多次调用
。
以是为相识决这一标题呢,我们可以
在每一个哀求上,再加上一个随机串nonce
,客户端每个哀求的nonce我都记录下来,那么下一次再次哀求的时候,就先根据nonce查一下,有没有哀求过,哀求过就丢弃,没有就正常处理。
好比这个接口:
curl -v -H 'X-TimeStamp: 1680503150' -H 'X-Nonce: wX5krzyVHuaYS8Ta' 'http://127.0.0.1:8080/testGet?p=testp&ab=123&x=456'
复制代码
我们在Header里,多传了一个X-Nonce,值为wX5krzyVHuaYS8Ta(随机生成的),
为了防止别人篡改呢,也需要将其作为署名的数据
,好比固定参数名为nonce,放置在timestamp后面,也不参与排序,那么待署名数据就变成了:
ab=123&p=testp&x=456
&path=/testGet×tamp=1680503150&nonce=wX5krzyVHuaYS8Ta
复制代码
注意事项
如果客户端超时重传,需要产生新的Nonce,要不可能会被拒
Nonce需要共同Timestamp一起,好比将Nonce存放到Redis,给
Nonce设置一个逾期时间,这个逾期时间可以为Timestamp的有效期
如果条件允许,可以将Nonce缓存独立出来,避免故障引起服务不可用
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4