参考:https://blog.csdn.net/wanghong7936/article/details/99077633?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-6.not_use_machine_learn_pai

因为前后端分离,所以接口必须暴露在公网环境,某些恶意用户会通过浏览器控制台查看接口,然后使用HTTP请求工具调用接口,因为请求工具可以伪造请求头等信息,通过请求头判断是否为恶意请求难度比较大,所以要对参数进行签名。

前端参数签名操作方法

  1. // 1. 传给后端的参数对象,增加时间戳参数
  2. let data = {id: 1, name: 11, channel_id:1, timestamp: 123456789};
  3. // 2. 获取data的key,排序规则按照第一个字符的ASCII码值递增排序
  4. let keys = Object.keys(data).sort()
  5. // 3. 将参数按照一定的规则拼接成字符串
  6. let buff = '';
  7. keys.forEach((key) => {
  8. buff += key + '=' + data[key] + '&'
  9. })
  10. buff = buff.substr(0, buff.length - 1)
  11. // 4. 加密拼接好的字符串
  12. signature = encrypt(buff);
  13. // 5. 将密文传给后端
  14. data.signature = signature;
  15. /**
  16. * 加密方法
  17. * @param buff
  18. */
  19. function encrypt(buff) {
  20. // 进入签名加密操作
  21. return buff;
  22. }

后端签名校验方法

  1. /**
  2. * 前端参数加密,防开挂校验,防止篡改参数,防止重复调用
  3. * @param array $params 前端传的所有参数
  4. * @throws BusinessException
  5. */
  6. public static function checkSignature(array $params) {
  7. if (!self::isNotEmpty($params, BasicConstant::SIGNATURE))
  8. throw new BusinessException('参数错误,缺少签名');
  9. Log::info('前端参数,排序前: ' . json_encode($params));
  10. // 1. 参数排序
  11. ksort($params);
  12. Log::info('排序后: ' . json_encode($params));
  13. // 2. 将参数拼接成字符串,除了 signature 签名之外都用 key=value& 的方式拼接
  14. $buff = '';
  15. foreach ($params as $k => $v) {
  16. if ($k != BasicConstant::SIGNATURE) {
  17. $buff .= $k . "=" . $v . "&";
  18. }
  19. }
  20. // 去除最后一个多余的 &
  21. $buff = trim($buff, "&");
  22. Log::info('拼接后: ' . $buff);
  23. // 3. 将签名放入 redis,如果 redis 中存在此签名,说明重复请求
  24. $encrypt = self::desEncrypt($buff);
  25. Log::info('加密后的密文: ' . $encrypt);
  26. $exists = RedisService::setExNx($encrypt, true, 10);
  27. if (!$exists)
  28. throw new BusinessException("非法请求,重复调用");
  29. // 4. 解密校验参数
  30. $decrypt = self::desDecrypt($params[BasicConstant::SIGNATURE]);
  31. Log::info('解密:' . $decrypt);
  32. // 如果签名解密后与接收到的实际参数不一致,说明参数被篡改
  33. if ($buff != $decrypt)
  34. throw new BusinessException('非法请求,参数可能被篡改');
  35. $decryptParams = self::convertUrlQuery($decrypt);
  36. Log::info('解密后解析成数组:' . json_encode($decryptParams));
  37. // 判断是否超时
  38. if (time() - $decryptParams['timestamp'] > 10)
  39. throw new BusinessException('签名超时');
  40. }
  41. /**
  42. * 自定义解密方法
  43. * @param $string
  44. * @return string
  45. */
  46. public static function desEncrypt($string)
  47. {
  48. return $string;
  49. }
  50. /**
  51. * 自定义加密方法
  52. * @param $string
  53. * @return string
  54. */
  55. public static function desDecrypt($string)
  56. {
  57. return $string;
  58. }

这样就能实现接口恶意调用的校验了,如果用户拿参数去重复调用的话会提示重复调用,如果用户修改了参数的话会提示参数被篡改。