GVKun编程网logo

开放接口的安全验证方案(AES+RSA)(开放api接口安全处理)

7

在本文中,我们将带你了解开放接口的安全验证方案(AES+RSA)在这篇文章中,我们将为您详细介绍开放接口的安全验证方案(AES+RSA)的方方面面,并解答开放api接口安全处理常见的疑惑,同时我们还将

在本文中,我们将带你了解开放接口的安全验证方案(AES+RSA)在这篇文章中,我们将为您详细介绍开放接口的安全验证方案(AES+RSA)的方方面面,并解答开放api接口安全处理常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的API 接口的安全设计验证:ticket,签名,时间戳、api接口安全验证功能的实现、API接口的安全设计验证:ticket,签名,时间戳、App 开放接口 API 安全性 —Token 签名 sign 的设计与实现

本文目录一览:

开放接口的安全验证方案(AES+RSA)(开放api接口安全处理)

开放接口的安全验证方案(AES+RSA)(开放api接口安全处理)

随着密码分析技术的提高,新的数据加密标准AES取代了过时的DES。文章在阐述AES/RSA加密算法的基础上,分别给出了利用AES/RSA实现客户端/服务器端网络数据传输的加密流程。最后在比较AES算法和RSA算法基础上,将AES与RSA相结合提出一种新的数据加密方案。

基本需求及概念

随着Internet网的广泛应用,信息安全问题日益突出,以数据加密技术为核心的信息安全技术也得到了极大的发展。目前的数据加密技术根据加密密钥类型可分私钥加密(对称加密)系统和公钥加密(非对称加密)系统[1]。对称加密算法是较传统的加密体制,通信双方在加/解密过程中使用他们共享的单一密钥,鉴于其算法简单和加密速度快的优点,目前仍然是主流的密码体制之一。最常用的对称密码算法是数据加密标准(DES)算法,但是由于DES密钥长度较短,已经不适合当今分布式开放网络对数据加密安全性的要求。最后,一种新的基于Rijndael算法对称高级数据加密标准AES取代了数据加密标准DES。非对称加密由于加/解密钥不同(公钥加密,私钥解密),密钥管理简单,也得到广泛应用。RSA是非对称加密系统最著名的公钥密码算法。

AES算法

基本原理及算法流程

美国国家标准和技术研究所(NIST)经过三轮候选算法筛选,从众多的分组密码中选中Rijndael算法作为高级加密标准(AES)。Rijndael密码是一个迭代型分组密码,分组长度和密码长度都是可变的,分组长度和密码长度可以独立的指定为128比特,192比特或者256比特。AES的加密算法的数据处理单位是字节,128位的比特信息被分成16个字节,按顺序复制到一个4*4的矩阵中,称为状态(state),AES的所有变换都是基于状态矩阵的变换。
用Nr表示对一个数据分组加密的轮数(加密轮数与密钥长度的关系如表1所示)。在轮函数的每一轮迭代中,包括四步变换,分别是字节代换运算(ByteSub())、行变换(ShiftRows())、列混合(MixColumns())以及轮密钥的添加变换AddRoundKey()[3],其作用就是通过重复简单的非线形变换、混合函数变换,将字节代换运算产生的非线性扩散,达到充分的混合,在每轮迭代中引入不同的密钥,从而实现加密的有效性。
表1 是三种不同类型的AES加密密钥分组大小与相应的加密轮数的对照表。加密开始时,输入分组的各字节按表2 的方式装入矩阵state中。如输入ABCDEFGHIJKLMNOP,则输入块影射到如表2的状态矩阵中。
表1:

1
2
3
4
|AES类型| 密钥长度 | 分组长度 | 加密轮数|
|AES-128| 4字 | 4字 | 10 |
|AES-192| 6字 | 4字 | 12 |
|AES-256| 8字 | 4字 | 14 |


表2:

1
2
3
4
| A | E | I | M |
| B | F | J | N |
| C | G | K | O |
| D | H | L | P |


  1. 字节代换运算(ByteSub())
    字节代换运算是一个可逆的非线形字节代换操作,对分组中的每个字节进行,对字节的操作遵循一个代换表,即S盒。S盒由有限域 GF(28)上的乘法取逆和GF(2)上的仿射变换两步组成。

  2. 行变换ShiftRows()
    行变换是一种线性变换,其目的就是使密码信息达到充分的混乱,提高非线形度。行变换对状态的每行以字节为单位进行循环右移,移动字节数根据行数来确定,第0行不发生偏移,第一行循环右移一个字节,第二行移两个,依次类推。

  3. 列混合变换MixColumns()
    列变换就是从状态中取出一列,表示成多项式的形式后,用它乘以一个固定的多项式a(x),然后将所得结果进行取模运算,模值为 x4+1。其中a(x)={03}x3+{02}x2+{01}x+{02},
    这个多项式与x4+1互质,因此是可逆的。列混合变换的算术表达式为:s’(x)= a(x) s(x),其中, s(x)表示状态的列多项式。

  4. 轮密钥的添加变换AddRoundKey()
    在这个操作中,轮密钥被简单地异或到状态中,轮密钥根据密钥表获得,其长度等于数据块的长度Nb。

AES算法流程

对于发送方,它首先创建一个AES私钥,并用口令对这个私钥进行加密。然后把用口令加密后的AES密钥通过Internet发送到接收方。发送方解密这个私钥,并用此私钥加密明文得到密文,密文和加密后的AES密钥一起通过Internet发送到接收方。接收方收到后再用口令对加密密钥进行解密得到AES密钥,最后用解密后的密钥把收到的密文解密成明文。图1中是这个过程的实现流程。
图1:

RSA算法

基本原理及流程

RSA是在1977年发明RSA密码系统的三个人的名字的首字母的缩写,他们是:Ron Rivest、Adi Shamir和Leonard Adleman。它是第一个公钥加密算法,在很多密码协议中都有应用,如SSL和S/MIME。RSA算法是基于大质数的因数分解的公匙体系。简单的讲,就是两个很大的质数,一个作为公钥,另一个作为私钥,如用其中一个加密,则用另一个解密。密钥长度从40到2048位可变,密钥越长,加密效果越好,但加密解密的开销也大。RSA算法可简单描述如下:

1
2
3
4
5
6
公开密钥:n=pq,(p,q为两个不同的很大的质数,p和q必须保密)
将(p-1)和(q-1)相乘得到φ(n)
选择一个整数e (1<e<φ(n))与φ(n)互质
秘密密钥:d=e-1modφ(n),即计算一个数字d,使得它满足公式 de=1 modφ(n)
加密:c=mc(mod n)
解密:m=cd(mod n),m为明文,c为密文。


RSA算法实现流程

首先,接收方创建RSA密匙对,即一个公钥和一个私钥,公钥被发送到发送方,私钥则被保存在接收方。发送方在接收到这个公钥后,用该公钥对明文进行加密得到密文,然后把密文通过网络传输给接收方。接收方在收到它们后,用RSA私钥对收到的密文进行解密,最后得到明文。图2是整个过程的实现流程。
图2:

AES与RSA相结合数据加密方案

RSA算法是公开密钥系统的代表,其安全性建立在具有大素数因子的合数,其因子分解困难这一法则之上的。Rijndael算法作为新一代的高级加密标准,运行时不需要计算机有非常高的处理能力和大的内存,操作可以很容易的抵御时间和空间的攻击,在不同的运行环境下始终能保持良好的性能。这使AES将安全,高效,性能,方便,灵活性集于一体,理应成为网络数据加密的首选。相比较,因为AES密钥的长度最长只有256比特,可以利用软件和硬件实现高速处理,而RSA算法需要进行大整数的乘幂和求模等多倍字长处理,处理速度明显慢于AES[5];所以AES算法加解密处理效率明显高于RSA算法。在密钥管理方面,因为AES算法要求在通信前对密钥进行秘密分配,解密的私钥必须通过网络传送至加密数据接收方,而RSA采用公钥加密,私钥解密(或私钥加密,公钥解密),加解密过程中不必网络传输保密的密钥;所以RSA算法密钥管理要明显优于AES算法。
从上面比较得知,由于RSA加解密速度慢,不适合大量数据文件加密,因此在网络中完全用公开密码体制传输机密信息是没有必要,也是不太现实的。AES加密速度很快,但是在网络传输过程中如何安全管理AES密钥是保证AES加密安全的重要环节。这样在传送机密信息的双方,如果使用AES对称密码体制对传输数据加密,同时使用RSA不对称密码体制来传送AES的密钥,就可以综合发挥AES和RSA的优点同时避免它们缺点来实现一种新的数据加密方案。加解密实现流程如图(3)。
图3:

具体过程是先由接收方创建RSA密钥对,接收方通过Internet发送RSA公钥到发送方,同时保存RSA私钥。而发送方创建AES密钥,并用该AES密钥加密待传送的明文数据,同时用接受的RSA公钥加密AES密钥,最后把用RSA公钥加密后的AES密钥同密文一起通过Internet传输发送到接收方。当接收方收到这个被加密的AES密钥和密文后,首先调用接收方保存的RSA私钥,并用该私钥解密加密的AES密钥,得到AES密钥。最后用该AES密钥解密密文得到明文。

AES+RSA结合最佳实践

基本要求

  1. 保证传输数据的安全性

  2. 保证数据的完整性

  3. 能够验证客户端的身份

基本流程

1
2
3
4
5
6
7
8
9
10
11
请求:
1. 服务器端(server)和客户端(client)分别生成自己的密钥对
2. serverclient分别交换自己的公钥
3. client生成AES密钥(aesKey)
4. client使用自己的RSA私钥(privateKey)对请求明文数据(params)进行数字签名
5. 将签名加入到请求参数中,然后转换为json格式
6. client使用aesKey对json数据进行加密得到密文(data)
7. client使用sever的RSA公钥对aesKey进行加密(encryptkey)
8. 分别将data和encryptkey作为参数传输给服务器端

服务器端进行请求响应时将上面流程反过来即可

原文地址:http://wustrive2008.github.io/2015/08/21/%E5%BC%80%E6%94%BE%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%AE%89%E5%85%A8%E9%AA%8C%E8%AF%81%E6%96%B9%E6%A1%88%28AES+RSA%29/


关注我们的方法:
1.点击文章标题下的“dotNET跨平台”蓝字,或者在微信搜索“opendotnet”,加关注
2.老朋友点击点击右上角“……”标志分享到朋友圈


本文分享自微信公众号 - dotNET跨平台(opendotnet)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

API 接口的安全设计验证:ticket,签名,时间戳

API 接口的安全设计验证:ticket,签名,时间戳

1.与前端对接的API接口,如果被第三方抓包并进行恶意篡改参数,可能会导致数据泄露,甚至会被篡改数据

2.与第三方公司的接口对接,第三方如果得到你的接口文档,但是接口确没安全校验,是十分不安全的

我主要围绕时间戳,token,签名三个部分来保证API接口的安全性

API接口的安全设计验证通常包括以下几个方面:ticket机制、签名验证、时间戳验证。

导图:
API接口的安全设计验证:

  • Ticket

    • 用途: 标识和验证用户身份
    • 实现方式:

      • 用户登录成功后生成一个ticket,并将其返回给用户
      • 用户在每次请求API时,都需要将ticket作为参数发送给服务器
      • 服务器端验证ticket的有效性,以确认用户的身份
    • 注意事项:

      • ticket应具有一定的时效性,避免安全漏洞
      • ticket应采用加密算法生成,提高安全性
  • 签名

    • 用途: 验证数据的完整性和真实性
    • 实现方式:

      • 将请求参数按照预定规则排序后,进行加密生成签名
      • 将签名作为参数发送给服务器端
      • 服务器端通过相同的规则对请求参数进行排序,并使用同样的加密算法生成签名
      • 对比服务器端生成的签名和请求中传递的签名,以验证数据的完整性和真实性
    • 注意事项:

      • 签名中应包含时间戳,以避免重放攻击
      • 加密算法应为不可逆的,确保数据的安全性
  • 时间戳

    • 用途: 避免重放攻击和保证数据的时效性
    • 实现方式:

      • 在API请求中添加一个时间戳参数,表示请求的时间
      • 服务器端接收到请求后,比较时间戳与当前时间的差距
      • 如果时间差超过一定范围,则判定请求为无效
    • 注意事项:

      • 时间戳应使用可靠的时钟来源,以确保准确性
      • 时间戳的有效范围需要根据实际需求设定

正文:

  1. Ticket机制:Ticket机制是一种用户身份验证的方式。在API接口请求中,客户端通常需要提供一个有效的Ticket,来证明自己的身份合法。服务端会根据Ticket进行身份验证,并根据验证结果决定是否授权请求。
  2. 签名验证:签名验证是一种对请求参数和密钥进行加密的方式,用于验证请求数据的完整性和真实性。客户端在发送请求时,会将请求参数和密钥进行加密,并将签名值作为请求参数之一发送给服务端。服务端通过验证签名值的正确性,来判断请求是否被篡改。
  3. 时间戳验证:时间戳验证用于验证请求的有效期。客户端在发送请求时,会附带一个时间戳参数,表示请求的发起时间。服务端会检查时间戳是否在一定的有效期内,如果超过有效期,则认为请求已过期。

这些安全设计验证措施可以有效防止未授权访问、请求篡改和重放攻击等安全问题。同时,为了进一步提升安全性,还可以结合其他安全措施,如使用HTTPS协议进行数据传输、限制API请求频率等。

Ticket机制是一种用于管理和控制系统资源访问的流程。以下是Ticket机制的典型流程:

  1. 用户请求资源:用户向系统发起资源访问请求,例如请求访问某个文件或执行某个操作。
  2. Ticket生成:系统根据用户请求生成一个唯一的Ticket,并将其分配给用户。Ticket通常包含一些关键信息,如用户身份、访问权限和有效期等。
  3. Ticket传递:系统将生成的Ticket传递给用户。通常,这可以通过将Ticket作为响应返回给用户的方式实现。
  4. Ticket验证:用户在访问资源时,将Ticket提供给系统进行验证。系统会检查Ticket的有效性,并验证用户是否具有访问该资源的权限。
  5. 资源访问授权:如果Ticket有效且用户具备访问权限,系统会授予用户对资源的访问授权。用户可以继续访问资源,执行所需的操作。
  6. Ticket作废:一旦用户完成资源访问或Ticket过期,系统将作废Ticket,不再接受该Ticket的验证请求。

Ticket机制的优势在于可以通过有效的身份验证和访问控制,确保用户只能访问其具有权限的资源,并提供一定程度的安全性和保护。同时,Ticket可以用于跟踪和记录用户的活动,方便系统监控和审计。

签名验证的流程如下:

  1. 客户端发送一个请求给服务器,并附带了一个签名。
  2. 服务器接收到请求后,首先从请求中提取出签名。
  3. 服务器获取请求所需的数据,并采用相同的签名算法对这些数据进行签名,并生成一个新的签名。
  4. 服务器将生成的签名与请求中的签名进行比较。
  5. 如果两个签名一致,则说明请求的签名是有效的,服务器可以接受并处理请求。
  6. 如果两个签名不一致,则说明请求的签名是无效的,服务器拒绝接受请求。

通过以上流程,服务器可以验证请求中的签名是否有效,从而确保请求的合法性。

时间戳验证:
时间戳验证流程是一种验证数字文件或数据的完整性和不可篡改性的方法。以下是常用的时间戳验证流程:

  1. 生成哈希值:首先,对要验证的文件或数据生成一个哈希值。哈希算法会将原始数据转换为一个固定长度的字符串,该字符串唯一地表示原始数据。
  2. 获取时间戳:将生成的哈希值发送给一个可信任的时间戳服务提供商。时间戳服务提供商会将哈希值与当前的日期和时间一起记录,并为其生成一个时间戳。
  3. 时间戳签名:时间戳服务提供商会使用其私钥对哈希值和时间戳进行数字签名。
  4. 返回时间戳:时间戳服务提供商将签名后的时间戳返回给用户。
  5. 验证时间戳:用户可以使用时间戳服务提供商的公钥来验证时间戳的有效性。首先,用户使用公钥来验证时间戳的数字签名是否有效。如果签名有效,则可以确定时间戳是由时间戳服务提供商生成的且未被篡改过的。
  6. 验证哈希值:用户还可以使用原始的文件或数据生成哈希值,并将其与

参考资料:
https://www.cnblogs.com/tongcc/p/15889802.html

api接口安全验证功能的实现

api接口安全验证功能的实现

这次给大家带来api接口安全验证功能的实现,实现api接口安全验证功能的注意事项有哪些,下面就是实战案例,一起来看一下。

php的api接口

在实际工作中,使用PHP写api接口是经常做的,PHP写好接口后,前台就可以通过链接获取接口提供的数据,而返回的数据一般分为两种情况,xml和json,在这个过程中,服务器并不知道,请求的来源是什么,有可能是别人非法调用我们的接口,获取数据,因此就要使用安全验证。

验证原理

示意图

原理

从图中可以看得很清楚,前台想要调用接口,需要使用几个参数生成签名。

时间戳:当前时间

随机数:随机生成的随机数

口令:前后台开发时,一个双方都知道的标识,相当于暗号

算法规则:商定好的运算规则,上面三个参数可以利用算法规则生成一个签名。

前台生成一个签名,当需要访问接口的时候,把时间戳,随机数,签名通过URL传递到后台。后台拿到时间戳,随机数后,通过一样的算法规则计算出签名,然后和传递过来的签名进行对比,一样的话,返回数据。

算法规则

在前后台交互中,算法规则是非常重要的,前后台都要通过算法规则计算出签名,至于规则怎么制定,看你怎么高兴怎么来。

我这个算法规则是

1 时间戳,随机数,口令按照首字母大小写顺序排序

2 然后拼接成字符串

3 进行sha1加密

4 再进行MD5加密

5 转换成大写。

前台

这里我并没有实际的前台,直接使用一个PHP文件代替前台,然后通过CURL模拟GET请求。我使用的是TP框架,URL格式是pathinfo格式。

源代码

<?php /**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/3/16 0016
 * Time: 15:56
 */
namespace Client\Controller;
use Think\Controller;
class ClientController extends Controller{
 const TOKEN = &#39;API&#39;;
 //模拟前台请求服务器api接口
 public function getDataFromServer(){
  //时间戳
  $timeStamp = time();
  //随机数
  $randomStr = $this -> createNonceStr();
  //生成签名
  $signature = $this -&gt; arithmetic($timeStamp,$randomStr);
  //url地址
  $url = "http://www.apitest.com/Server/Server/respond/t/{$timeStamp}/r/{$randomStr}/s/{$signature}";
  $result = $this -&gt; httpGet($url);
  dump($result);
 }
 //curl模拟get请求。
 private function httpGet($url){
  $curl = curl_init();
  //需要请求的是哪个地址
  curl_setopt($curl,CURLOPT_URL,$url);
  //表示把请求的数据已文件流的方式输出到变量中
  curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
  $result = curl_exec($curl);
  curl_close($curl);
  return $result;
 }
 //随机生成字符串
 private function createNonceStr($length = 8) {
  $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  $str = "";
  for ($i = 0; $i <p><span><strong>服务器端</strong></span></p><p>接受前台数据进行验证</p><p><strong>源代码</strong></p><pre><?php /**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/3/16 0016
 * Time: 16:01
 */
namespace Server\Controller;
use Think\Controller;
class ServerController extends Controller{
 const TOKEN = &#39;API&#39;;
 //响应前台的请求
 public function respond(){
  //验证身份
  $timeStamp = $_GET[&#39;t&#39;];
  $randomStr = $_GET[&#39;r&#39;];
  $signature = $_GET[&#39;s&#39;];
  $str = $this -> arithmetic($timeStamp,$randomStr);
  if($str != $signature){
   echo "-1";
   exit;
  }
  //模拟数据
  $arr[''name''] = ''api'';
  $arr[''age''] = 15;
  $arr[''address''] = ''zz'';
  $arr[''ip''] = "192.168.0.1";
  echo json_encode($arr);
 }
 /**
  * @param $timeStamp 时间戳
  * @param $randomStr 随机字符串
  * @return string 返回签名
  */
 public function arithmetic($timeStamp,$randomStr){
  $arr[''timeStamp''] = $timeStamp;
  $arr[''randomStr''] = $randomStr;
  $arr[''token''] = self::TOKEN;
  //按照首字母大小写顺序排序
  sort($arr,SORT_STRING);
  //拼接成字符串
  $str = implode($arr);
  //进行加密
  $signature = sha1($str);
  $signature = md5($signature);
  //转换成大写
  $signature = strtoupper($signature);
  return $signature;
 }
}
登录后复制

结果

string(57) "{"name":"api","age":15,"address":"zz","ip":"192.168.0.1"}"
登录后复制

总结

这种方法只是其中的一种方法,其实还有很多方法都是可以进行安全验证的。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

PHP回调函数及匿名函数使用详解

phpstudy2018的访问目录服务权限

以上就是api接口安全验证功能的实现的详细内容,更多请关注php中文网其它相关文章!

API接口的安全设计验证:ticket,签名,时间戳

API接口的安全设计验证:ticket,签名,时间戳

概述

与前端对接的API接口,如果被第三方抓包并进行恶意篡改参数,可能会导致数据泄露,甚至会被篡改数据,我主要围绕时间戳,token,签名三个部分来保证API接口的安全性
在这里插入图片描述
1.用户成功登陆站点后,服务器会返回一个token,用户的任何操作都必须带了这个参数,可以将这个参数直接放到header里。

2.客户端用需要发送的参数和token生成一个签名sign,作为参数一起发送给服务端,服务端在用同样的方法生成sign进行检查是否被篡改。

3.但这依然存在问题,可能会被进行恶意无限制访问,这时我们需要引入一个时间戳参数,如果超时即是无效的。

4.服务端需要对token,签名,时间戳进行验证,只有token有效,时间戳未超时,签名有效才能被放行。

开放接口

没有进行任何限制,简单粗暴的访问方式,这样的接口方式一般在开放的应用平台,查天气,查快递,只要你输入正确对应的参数调用,即可获取到自己需要的信息,我们可以任意修改参数值。

/*
 * Description: 开放的接口
 * @author huangweicheng
 * @date 2020/12/21
*/
@RestController
@RequestMapping("/token")
public class TokenSignController {

    @Autowired
    private TokenSignService tokenSignService;

    @RequestMapping(value = "openDemo",method = RequestMethod.GET)
    public List<PersonEntity> openDemo(int personId){
        return tokenSignService.getPersonList(personId);
    }
}

Token认证获取

用户登录成功后,会获取一个ticket值,接下去任何接口的访问都需要这个参数。我们把它放置在redis内,有效期为10分钟,在ticket即将超时,无感知续命。延长使用时间,如果用户在一段时间内没进行任何操作,就需要重新登录系统。扩展:记一次token安全认证的实践

@RequestMapping(value = "login",method = RequestMethod.POST)
    public JSONObject login(@NotNull String username, @NotNull String password){
        return tokenSignService.login(username,password);
    }

登录操作,查看是否有这个用户,用户名和密码匹配即可成功登录。

/** 
     * 
     * Description:验证登录,ticket成功后放置缓存中,
     * @param
     * @author huangweicheng
     * @date 2020/12/31   
    */ 
    public JSONObject login(String username,String password){
        JSONObject result = new JSONObject();
        PersonEntity personEntity = personDao.findByLoginName(username);
        if (personEntity == null || (personEntity != null && !personEntity.getPassword().equals(password))){
            result.put("success",false);
            result.put("ticket","");
            result.put("code","999");
            result.put("message","用户名和密码不匹配");
            return result;
        }
        if (personEntity.getLoginName().equals(username) && personEntity.getPassword().equals(password)){
            String ticket = UUID.randomUUID().toString();
            ticket = ticket.replace("-","");
            redisTemplate.opsForValue().set(ticket,personEntity.getLoginName(),10L, TimeUnit.MINUTES);
            result.put("success",true);
            result.put("ticket",ticket);
            result.put("code",200);
            result.put("message","登录成功");
            return result;
        }
        result.put("success",false);
        result.put("ticket","");
        result.put("code","1000");
        result.put("message","未知异常,请重试");
        return result;
    }

Sign签名

把所有的参数拼接一起,在加入系统秘钥,进行MD5计算生成一个sign签名,防止参数被人恶意篡改,后台按同样的方法生成秘钥,进行签名对比。

/**
     * @param request
     * @return
     */
    public static Boolean checkSign(HttpServletRequest request,String sign){
        Boolean flag= false;
        //检查sigin是否过期
        Enumeration<?> pNames =  request.getParameterNames();
        Map<String, String> params = new HashMap<String, String>();
        while (pNames.hasMoreElements()) {
            String pName = (String) pNames.nextElement();
            if("sign".equals(pName)) continue;
            String pValue = (String)request.getParameter(pName);
            params.put(pName, pValue);
        }
        System.out.println("现在的sign-->>" + sign);
        System.out.println("验证的sign-->>" + getSign(params,secretKeyOfWxh));
        if(sign.equals(getSign(params, secretKeyOfWxh))){
            flag = true;
        }
        return flag;
    }

重复访问

引入一个时间戳参数,保证接口仅在一分钟内有效,需要和客户端时间保持一致。

public static long getTimestamp(){
        long timestampLong = System.currentTimeMillis();

        long timestampsStr = timestampLong / 1000;

        return timestampsStr;
    }

需要跟当前服务器时间进行对比,如果超过一分钟,就拒绝本次请求,节省服务器查询数据的消耗

拦截器

每次请求都带有这三个参数,我们都需要进行验证,只有在三个参数都满足我们的要求,才允许数据返回或被操作。

public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws IOException {
        JSONObject jsonObject = new JSONObject();
        String ticket = request.getParameter("ticket");
        String sign = request.getParameter("sign");
        String ts = request.getParameter("ts");
        if (StringUtils.isEmpty(ticket) || StringUtils.isEmpty(sign) || StringUtils.isEmpty(ts)){
            jsonObject.put("success",false);
            jsonObject.put("message","args is isEmpty");
            jsonObject.put("code","1001");
            PrintWriter printWriter = response.getWriter();
            printWriter.write(jsonObject.toJSONString());
            return false;
        }
        //如果redis存在ticket就认为是合法的请求
        if (redisTemplate.hasKey(ticket)){
            System.out.println(redisTemplate.opsForValue().getOperations().getExpire(ticket));
            String values = (String) redisTemplate.opsForValue().get(ticket);
            //判断ticket是否即将过期,进行续命操作
            if (redisTemplate.opsForValue().getOperations().getExpire(ticket) != -2 && redisTemplate.opsForValue().getOperations().getExpire(ticket) < 20){
                redisTemplate.opsForValue().set(ticket,values,10L, TimeUnit.MINUTES);
            }
            System.out.println(SignUtils.getTimestamp());
            //判断是否重复访问,存在重放攻击的时间窗口期
            if (SignUtils.getTimestamp() - Long.valueOf(ts) > 600){
                jsonObject.put("success",false);
                jsonObject.put("message","Overtime to connect to server");
                jsonObject.put("code","1002");
                PrintWriter printWriter = response.getWriter();
                printWriter.write(jsonObject.toJSONString());
                return false;
            }
            //验证签名
            if (!SignUtils.checkSign(request,sign)){
                jsonObject.put("success",false);
                jsonObject.put("message","sign is invalid");
                jsonObject.put("code","1003");
                PrintWriter printWriter = response.getWriter();
                printWriter.write(jsonObject.toJSONString());
                return false;
            }
            return true;
        }else {
            jsonObject.put("success",false);
            jsonObject.put("message","ticket is invalid,Relogin.");
            jsonObject.put("code","1004");
            PrintWriter printWriter = response.getWriter();
            printWriter.write(jsonObject.toJSONString());
        }
        return false;
    }
}

访问

先登录系统,获取合法的ticket
在这里插入图片描述
生成一个合法的sign验证,获取测试ts,访问openDemo,即可正常访问。还可以将参数加密,将http换成https,就不一 一展开了。
在这里插入图片描述
demo代码
https://github.com/hwc4110/sp...

cnblogs.com/dslx/p/14116294.html

App 开放接口 API 安全性 —Token 签名 sign 的设计与实现

App 开放接口 API 安全性 —Token 签名 sign 的设计与实现

在 app 开放接口 API 的设计中,避免不了的就是安全性问题。

一、HTTPS 协议

对于一些敏感的 API 接口,需要使用 https 协议。

https 是在 http 超文本传输协议加入 SSL 层,它在网络间通信是加密的,所以需要加密证书。

二、签名设计

原理:用户登录后向服务器提供用户认证信息(如账户和密码),服务器认证完后给客户端返回一个 Token 令牌,用户再次获取信息时,带上此令牌,如果令牌正确,则返回数据。对于获取 Token 信息后,访问用户相关接口,客户端请求的 url 需要带上如下参数:

时间戳:timestamp

Token 令牌:token

然后将所有用户请求的参数按照字母排序(包括 timestamp,token),然后更具 MD5 加密(可以加点盐),全部大写,生成 sign 签名,这就是所说的 url 签名算法。然后登陆后每次调用用户信息时,带上 sign,timestamp,token 参数。

其最终的原理是减小明文的暴露次数;保证数据安全的访问。

具体实现如下:

1. 客户端向服务器端发送用户认证信息(用户名和密码),服务器端接收到请求后,验证用户信息是否正确。

如果正确:则返回一个唯一不重复的字符串(一般为 UUID),然后在 Redis(任意缓存服务器)中维护 Token----Uid 的用户信息关系,以便其他 API 对 token 的校验。

如果错误:则返回错误码。

2. 服务器设计一个 url 请求拦截规则

(1)判断是否包含 timestamp,token,sign 参数,如果不含有返回错误码。

(2)判断服务器接到请求的时间和参数中的时间戳是否相差很长一段时间(时间自定义如半个小时),如果超过则说明该 url 已经过期(如果 url 被盗,他改变了时间戳,但是会导致 sign 签名不相等)。

(3)判断 token 是否有效,根据请求过来的 token,查询 redis 缓存中的 uid,如果获取不到这说明该 token 已过期。

(4)根据用户请求的 url 参数,服务器端按照同样的规则生成 sign 签名,对比签名看是否相等,相等则放行。(自然 url 签名 也无法 100% 保证其安全,也可以通过公钥 AES 对数据和 url 加密,但这样无法确保公钥丢失,所以签名只是很大程度上保证安全)。

(5)此 url 拦截只需对获取身份认证的 url 放行(如登陆 url),剩余所有的 url 都需拦截。

今天的关于开放接口的安全验证方案(AES+RSA)开放api接口安全处理的分享已经结束,谢谢您的关注,如果想了解更多关于API 接口的安全设计验证:ticket,签名,时间戳、api接口安全验证功能的实现、API接口的安全设计验证:ticket,签名,时间戳、App 开放接口 API 安全性 —Token 签名 sign 的设计与实现的相关知识,请在本站进行查询。

本文标签: