在一些特殊场景下,我们可能希望对于 GET 或 POST 进入到接口的数据进行签名和有效期的校验,例如 APP 请求后端接口的场景,我们通常需要考虑两个问题:
问题1:如何避免攻击者在捕获到接口请求后,自行构造请求参数,向接口发送请求,而不通过 APP 的正常界面进行操作。
问题2:在接口请求不可避免能被捕获的情况下,如何确保每一次请求能够过期,不被反复的利用,例如投票刷票的问题。
基于上面两个问题,我们在设计接口时,就需要通过给请求参数进行签名的方式来对数据来源和有效期进行校验。下面将以 MiniFramework 框架为例,演示如何通过 MiniFramework 框架来实现对请求参数进行签名和签名校验的方法。
首先,我们创建一个名为 Index 的控制器,并在控制器中创建名为 sign 和 verifysign 两个动作方法,分别用于生成签名,和校验签名,具体代码如下:
代码语言:javascript复制<?php
// 声明控制器命名空间
namespace AppController;
// 加载动作类
use MiniBaseAction;
// 加载签名类
use MiniSecuritySign;
class Index extends Action
{
/**
* 生成签名
*/
function signAction()
{
// 待签名的数据
$data = [
// 假设我们要通过GET方式传递参数info=MiniFramework
'info' => 'MiniFramework',
// signTime为当前时间戳,且必须随数据一起进行签名
'signTime' => time()
];
// 实例化签名类
$signObj = new Sign();
// 指定用 sha1 来进行加密(默认为:md5)
$signObj->setEncryptType('sha1');
// 获得一个签名
$sign = $signObj->sign($data);
// 签名随其他数据一起通过GET传递
$data['sign'] = $sign;
dump($data);
// 构造一个GET请求URL
$dataStr = arrayToUrlParams($data);
$url = $this->view->baseUrl() . '/index/verifysign?' . $dataStr;
echo '<a href="' . $url . '" target="_blank">点击这里跳转到签名验证页</a>';
die();
}
/**
* 验证签名
*/
function verifysignAction()
{
// 实例化
$signObj = new Sign();
// 验证时需要使用相同的加密方式
$signObj->setEncryptType('sha1');
// 设定签名过期时间为30秒(默认为:300秒)
$signObj->setExpireTime(30);
// 获得签名校验结果(传入参数get代表对GET请求进行签名校验)
$res = $signObj->verifySign('get');
if ($res === true) {
echo '签名有效';
} else {
echo '签名无效';
}
die();
}
}
完成上述代码编写后,我们可以通过浏览器访问这个控制器的 sign 动作方法,生成签名并构造一个跳转链接,通过跳转链接进入 verifysign 动作方法完成对请求的签名校验。
我们从代码中可以看到签名使用的是 sha1 加密算法,生成签名和校验签名要使用相关的加密算法,否则将无法正确进行校验。
签名的有效期在 verifysign 动作方法中通过 setExpireTime() 设定为30秒,那么从签名被生成开始,有效期为30秒,过期后的签名将无法通过校验。
上述针对签名校验的特性在 MiniFramework 的 2.4.0 版本中加入,示例代码可以在项目的 Example 控制器中找到。
获取 MiniFramework 源代码请移步至码云Gitee仓库:https://gitee.com/jasonwei/miniframework