接口安全设计之防篡改和防重放

07-19 1643阅读

概述

背景

之所以想跟大家分享怎么做好基础的接口安全,一方面是工作需要,之前这部分的工作是我在负责,所以正好有这部分的经验;二是我之前也接触过很多做后端的同学,对于这一块大部分涉及不深或不太了解,也不知道怎么样做才算相对安全。所以把我的想法写出来,供大家参考和讨论,共同学习和进步。

当然了,我分享的也只是我的个人经验,自然有很多的不足之处,也并不是说我后续阐述的一些观点和实现就一定是安全的,大家要加入自己的判断,并且混入一些定制化的东西

适用范围

本章节内容,主要说的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签名算法有几点跟大家提一提。

  1. 签名肯定都是私钥签名,公钥验签。
  2. 验签的复杂度比签名高,因为验签有两次点乘一次点加,而签名是一次点乘。
  3. 签名如果只有公钥的话,要多一次点乘,即从私钥生成公钥,所以服务器写签名算法,就把公私钥都保存起来,可以省掉一次点乘。
  4. 签名算法在计算z的时候,要传入userid,默认都是1234567812345678。这里如果是非标的话,可以定制和作文章,加大安全性。
  5. 签名需要随机生成大数 in [1, n - 1],不要偷懒,当然别人封装好的,一般都会处理。

集群部署

通常为满足集群部署,水平扩展的要求,我们需要把用户用于验签相关的内容缓存到内存中(比如Redis),以减少数据库这方面的查询压力。

注意事项

  1. 对于GET类的请求,通常的参数的值可能需要经过encodeURI处理,这里指的是拼装待签名数据的时候,请求传参时不需要
  2. 对于POST类请求,在写拦截器的时候,要定制InputStream,因为拦截验签的时候,会先把BODY读出来,所以处理完要写回去 ,或采用其它类似方法处理
  3. 这类非功能性需求,如果条件允许,可以将缓存用户公钥这类服务独立出来,增加服务的可用性。
  4. 前端和后端加密的参数一定要保证每个参数的数据类型一致 ,否则最后加密的结果可能不同(博主亲自踩的坑)

降级处理

针对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&timestamp=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&timestamp=1680503150&nonce=wX5krzyVHuaYS8Ta
    

    注意事项

    • 如果客户端超时重传,需要产生新的Nonce,要不可能会被拒

    • Nonce需要配合Timestamp一起,比如将Nonce存放到Redis,给Nonce设置一个过期时间,这个过期时间可以为Timestamp的有效期

    • 如果条件允许,可以将Nonce缓存独立出来,避免故障引起服务不可用

      学习网络安全技术的方法无非三种:

      第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。

      第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。

      如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

      第三种就是去找培训。

      接口安全设计之防篡改和防重放

      接下来,我会教你零基础入门快速入门上手网络安全。

      网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。

      第一阶段:基础准备 4周~6周

      这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇

      接口安全设计之防篡改和防重放

      第二阶段:web渗透

      学习基础 时间:1周 ~ 2周:

      ① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。

      ② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。

      ③ 学会提问的艺术,如果遇到不懂得要善于提问。

      接口安全设计之防篡改和防重放

      配置渗透环境 时间:3周 ~ 4周:

      ① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。

      ② 下载这些工具无后门版本并且安装到计算机上。

      ③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。

      渗透实战操作 时间:约6周:

      ① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。

      ② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。

      ③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。

      ④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。

      ⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。

      ⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。

      ⑦ 了解一句话木马,并尝试编写过狗一句话。

      ⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权

      接口安全设计之防篡改和防重放

      以上就是入门阶段

      第三阶段:进阶

      已经入门并且找到工作之后又该怎么进阶?详情看下图

      接口安全设计之防篡改和防重放

      给新手小白的入门建议:

      新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!

      如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

      接口安全设计之防篡改和防重放

      接口安全设计之防篡改和防重放

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]