PHP 如何设计一个高安全的电商平台:淘宝/京东商品类API封装接口

news2025/2/26 15:11:18

电商API接口有哪些安全问题?

图片

如何保证API接口安全

接口的安全性主要围绕Token、Timestamp和Sign三个机制展开设计,保证接口的数据不会被篡改和重复调用,下面具体来看:

Token授权机制:用户使用用户名密码登录后服务器给客户端返回一个Token(通常是UUID),并将Token-UserId以键值对的形式存放在缓存服务器中。服务端接收到请求后进行Token验证,如果Token不存在,说明请求无效。

图片

时间戳超时机制:用户每次请求都带上当前时间的时间戳timestamp,服务端接收到timestamp后跟当前时间进行比对,如果时间差大于一定时间(比如5分钟),则认为该请求失效,这个时间要保证足够完成本次请求的同时尽量短,可以减少缓存服务器的压力(见签名机制)。

签名机制:将Token和时间戳加上其他请求参数就行MD5或SHA-1算法(可根据情况加点盐)加密,加密后的数据为本次请求的签名sign,并将该签名存放到缓存服务器中,超时时间设定为跟时间戳的超时时间一致(这就是为什么要尽量短,二者时间一致可以保证无论在timestamp规定时间内还是外本URL都只能访问一次)。服务端接收到请求后以同样的算法得到签名,并跟当前的签名进行比对,如果不一样,说明参数被更改过,直接返回错误标识。同一个签名只能使用一次,如果发现缓存服务器中已经存在了本次签名,则拒绝服务。

sign生成规则及步骤:

① 第一步:将所有需要发送至服务端的请求参数(空参数值的参数、文件、字节流、sign除外)按照参数名ASCII码从小到大排序(字典序)

注意:

      l 参数名ASCII码从小到大排序(字典序);

      l 如果参数的值为空不参与签名;

      l 文件、字节流不参与签名;

      l sign不参与签名;

      l 参数名、参数值区分大小写;

②第二步:将排序后的参数按照URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串strA;

③第三步:在strA后面拼接上apiKey得到striSignTemp字符串,将strSignTemp字符串转换为小写字符串后进行MD5运算,MD5运算后得到值作为sign的值传入服务端;

/* * @desc 签名函数 * @param $paramArr 系统参数 * @param $apiKey 私钥 * @return string 返回签名 */private function createSign ($paramArr,$apiKey) {    ksort($paramArr);    $sign='';
    foreach ($paramArr as $key => $val) {        if ($key != '' && $val != '') {            $sign .= $key."=".$val."&";        }    }    $sign=rtrim($sign,"&");    $sign.=$apiKey;    $sign=strtolower($sign);    $sign = md5($sign);    return $sign;}

签名校验:

/* * @desc 签名校验 * @param $token string 服务端分配的标识(不同客户端需使用不同的标识) * @param $timestamp string 时间戳,UTC时间,以北京时间东八区(+8)为准 * @param $sign string 签名 * @param $privatekey string 私钥 * @param $data 业务参数json格式 * @return bool */private function checkAuth($token,$timestamp,$sign,$privatekey,$data){        //参数判断        if(empty($token)){            show(10001,'token不能为空!');        }                if(empty($timestamp)){            show(10002,'时间戳不能为空!');        }                if(empty($data)){            show(10004,'业务参数不能为空!');        }                if(empty($sign)){            show(10006,'签名不能为空!');        }                if(empty($privatekey)){            show(10007,'私钥不能为空!');        }        //时间校验        $expire_second=config('expire_second');        $timestamp_t=$timestamp+$expire_second;        if($timestamp_t<time()){             show(10008,'请求已经过期!');        }        //系统参数        $paramArr=array(            'token'=>$token,            'timestamp'=>$timestamp,            'data'=>$data,        );
        //按规则拼接为字符串        $str = $this->createSign($paramArr,$this->privatekey);         if($str != $this->sign){             show(10009,'验签错误!');        }        return true;    }

拒绝重复调用:客户端第一次访问时,将签名sign存放到缓存服务器中,超时时间设定为跟时间戳的超时时间一致,二者时间一致可以保证无论在timestamp限定时间内还是外 URL都只能访问一次。如果有人使用同一个URL再次访问,如果发现缓存服务器中已经存在了本次签名,则拒绝服务。如果在缓存中的签名失效的情况下,有人使用同一个URL再次访问,则会被时间戳超时机制拦截。这就是为什么要求时间戳的超时时间要设定为跟时间戳的超时时间一致。拒绝重复调用机制确保URL被别人截获了也无法使用(如抓取数据)。

/** * @desc 限制请求接口次数 * @return bool */private function ask_count(){    $client_ip = $this->sys_get_client_ip();    $ask_url = $this->sys_GetCurUrl();    //限制次数    $limit_num = config('api_ask_limit');     //有效时间内,单位:秒    $limit_time = config('api_ask_time');     $now_time = time();    $valid_time = $now_time - $limit_time;    $ipwhere['ip_name'] = $client_ip;    $ipwhere['ask_url'] = $ask_url;    $ipwhere['creatime'] = array('>=',date('Y-m-d H:i:s',$valid_time));    $check_result = Db::table('log_ip_ask')->where($ipwhere)->count();      if($check_result !=='0'){          if($check_result >= $limit_num){              show(10010,'已经超出了限制次数!');        }      }        //执行插入    $add_data = array(        'ip_name'=>$client_ip,        'ask_url'=>$ask_url,        'creatime'=>date('Y-m-d H:i:s',time())    );    $result = Db::table('log_ip_ask')->insert($add_data);    if($result===false){         show(10011,'限制次数写入记录失败!');    }        return true;}

/** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @param boolean $adv 是否进行高级模式获取(有可能被伪装)  * @return mixed */private function sys_get_client_ip($type = 0,$adv=false) {    $type = $type ? 1 : 0;    static $ip  =   NULL;    if ($ip !== NULL) return $ip[$type];    if($adv){        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);            $pos    =   array_search('unknown',$arr);            if(false !== $pos) unset($arr[$pos]);            $ip     =   trim($arr[0]);        }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {            $ip     =   $_SERVER['HTTP_CLIENT_IP'];        }elseif (isset($_SERVER['REMOTE_ADDR'])) {            $ip     =   $_SERVER['REMOTE_ADDR'];        }    }elseif (isset($_SERVER['REMOTE_ADDR'])) {        $ip = $_SERVER['REMOTE_ADDR'];    }    // IP地址合法验证    $long = sprintf("%u",ip2long($ip));    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);    return $ip[$type];}
/** * @desc php获取当前访问的完整url地址 * @return string */private function sys_GetCurUrl() {    $url = 'http://';    if (isset ( $_SERVER ['HTTPS'] ) && $_SERVER ['HTTPS'] == 'on') {        $url = 'https://';    }    if ($_SERVER ['SERVER_PORT'] != '80') {        $url .= $_SERVER ['HTTP_HOST'] . ':' . $_SERVER ['SERVER_PORT'] . $_SERVER ['REQUEST_URI'];    } else {        $url .= $_SERVER ['HTTP_HOST'] . $_SERVER ['REQUEST_URI'];    }    return $url;}

非法ip限制访问:此处的限制一般用在服务器间的接口调用

// 允许访问的IP列表        private $ip_allow = array(        '192.168.0.111',        '192.168.0.112',        '192.168.0.113',    );
   /**     * @desc 非法IP限制访问     * @param array $config     * @return bool     */   private function illegalip(){        if(!$this->ip_limit){            return true;        }        $remote_ip = get_client_ip();        if(in_array($remote_ip, $ip_allow)){            return true;        }        return false;    }

传输安全HTTPS

互联网发展到今天,大家越来越重视自己的隐私,各大公司也越来越重视数据的安全。传输过程中的数据安全解决方案主要是“HTTPS”,能够有效防止中间人攻击等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/990633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML5Plus

之前写过在 vue 中使用 mui 框架的方法&#xff0c;因为用 vue 开发后打包 5App 会有一些问题&#xff0c;所以当时用到了&#xff0c;最近又一次开发移动端&#xff0c;不同的是这次使用的是 vue3 开发的&#xff0c;导致之前使用的 vue-awesome-mui 依赖不能使用了&#xff0…

Redis原理:IntSet

&#xff08;笔记总结自b站黑马程序员课程&#xff09; 一、结构 IntSet是Redis中set集合的一种实现方式&#xff0c;基于整数数组来实现&#xff0c;并且具备长度可变、有序等特征。 结构如下&#xff1a; typedef struct intset {uint32_t encoding; //编码方式uint32_t l…

计算机视觉领域经典模型汇总(2023.09.08

一、RCNN系列 1、RCNN RCNN是用于目标检测的经典方法&#xff0c;其核心思想是将目标检测任务分解为两个主要步骤&#xff1a;候选区域生成和目标分类。 候选区域生成&#xff1a;RCNN的第一步是生成可能包含目标的候选区域&#xff0c;RCNN使用传统的计算机视觉技术&#x…

Matlab 如何选择采样频率和信号长度

Matlab 如何选择采样频率和信号长度 1、概述 在实际信号分析中经常会遇到要分辨出频率间隔为 的两个分量&#xff0c;在这种情形中如何选择采样频率和信号的长度呢&#xff1f; 2、案例分析 设有一个信号由三个正弦信号组成&#xff0c;其频率分别为 &#xff0c;即&#xf…

流程图 and/or/xor 讲解

and表示后续2个活动同时触发&#xff0c; or表示后续2个活动可触发其中的1个或2个&#xff0c;无排他性&#xff0c;也就是每个活动的触发不影响其他活动&#xff1b; xor表示后续2个活动只触发一个&#xff0c;有排他性&#xff0c;也就是只能触发其中一个。 示例演示“OR”…

网络安全架构:建立安全架构方法的指导框架

01 关键发现 ■ 架构框架使用集体见解来创建最佳实践&#xff0c;指导用户考虑组织风险和业务环境。这些方法的改编和定制&#xff0c;将帮助组织从中获得最佳价值。 ■ 方法论提供了一种系统工程方法&#xff0c;使用业务输入和期望&#xff0c;来创建可重复、可跟踪&#xf…

React16、18 使用 Redux

Redux 核心 Redux 介绍 Redux 是javaScript 状态容器&#xff0c;提供可预测化的状态管理 Redux 工作流程 Actions&#xff1a;对象&#xff0c;描述对状态进行怎样的操作 Reducer&#xff1a;函数&#xff0c;操作状态并返回新的状态 Store&#xff1a;存储状态的容器&am…

【面试】Redis的热key问题如何发现和解决?

文章目录 背景一、怎么发现热key1.1 方法一:凭借业务经验&#xff0c;进行预估哪些是热key1.2 方法二:在客户端进行收集1.3 方法三:在Proxy层做收集1.4 方法四:用redis自带命令1.5 方法五:自己抓包评估 二、如何解决2.1. 利用二级缓存2.2. 备份热key2.3 永不过期2.4 分布式锁 三…

分享5个和安全相关的 VSCode 插件

开发高质量的软件应用程序可能是艰巨的&#xff0c;因为许多组成部分必须协同工作才能创建出一个可运行的解决方案。这就是为什么开发人员需要尽可能获得所有帮助和便利&#xff0c;特别是在保护他们的应用程序时。 Visual Studio Code&#xff08;VSCode&#xff09;是最受欢迎…

redis高可用——主从复制、哨兵模式、cluster集群

1、redis群集有三种模式 分别是主从同步/复制、哨兵模式、Cluster&#xff0c;下面会讲解一下三种模式的工作方式&#xff0c;以及如何搭建cIustr群集 主从复制:主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的…

jenkins创建用户

一.背景 之前用了很多次&#xff0c;现在转到甲方爸爸的岗位&#xff0c;要培养大学毕业生&#xff0c;才发现好记性不如烂笔头。给年轻人写出来。 二.创建用户的过程 1.用户管理界面入口 Dashboard>Manage Jenkins>Jenkins own user database 2.点击右边的按钮“Cre…

Arm 架构 Ubuntu 使用 Docker 安装 Gitlab 并使用

官方 gitlab 文档 我的系统是 arm 架构的 ubuntu 官网没有提供 arm 架构的 docker 的 gitlab 的安装方式&#xff0c;直接安装的也是后来加的&#xff0c;文档也是随笔带过&#xff0c;&#xff0c;&#xff0c;我用到了&#xff0c;记录一下 默认已经安装了 docker 在 docker …

【STM32】常用存储器

常用存储器 RAM 存储器 RAM 是“Random Access Memory”的缩写&#xff0c;被译为随机存储器。所谓“随机存取”&#xff0c;指的是当存储器中的消息被读取或写入时&#xff0c;所需要的时间与这段信息所在的位置无关。而RAM可随读取其内部任意地址的数据&#xff0c;时间都是…

Android 12.0 禁用系统app首次启动动画SplashScreen功能分析

1.前言 在12.0的系统开发中,由于系统增加了新特性,在app首次启动的时候,添加了启动引导动画SplashScreen功能,所以会默认显示 app图标作为一张动画来过度,解决首次启动卡顿问题,接下来分析下看是怎么样添加的,然后禁用就可以了 如图: 2.禁用系统app首次启动动画SplashSc…

关于mybatisplus报错:Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplat的问题

可能是mybatisplus版本不兼容的问题&#xff0c;我之前用的3.4.0&#xff0c;springboot版本是3.1.3&#xff0c;maven版本是3.8.8&#xff0c;运行的时候报了这个错。现在修改了mybatisplus的版本&#xff0c;如下图&#xff1a; 这样就不报错了。 大家可以在这里找合适的my…

DGA行为转变引发了对网络安全的担忧

Akamai的研究人员发现&#xff0c;在域名系统(DNS)流量数据中&#xff0c;动态种子域生成算法(DGA)家族的行为发生了令人担忧的变化。这一发现揭示了恶意行为者如何调整他们的策略来延长他们的指挥与控制(C2)通信通道的寿命&#xff0c;以保护他们的僵尸网络。 从技术角度来看…

Excel文件生成与下载(SpringBoot项目)(easypoi)

说明 通过接口&#xff0c;导出表格。 使用SpringBoot框架和easypoi表格解析框架&#xff0c;生成Excel表格&#xff0c;并通过接口下载。 表格示例 依赖 版本 <easypoi.version>4.4.0</easypoi.version>依赖 <!-- easypoi --> <dependency><…

Matlab图像处理之Lee滤波器

目录 一、前言:二、LEE滤波器2.1 LEE滤波器原理2.2 LEE滤波器实现步骤三、MATLAB代码示例一、前言: LEE滤波器是一种常用于合成孔径雷达(SAR)图像去噪的滤波器。它能增强图像的局部对比度。今天我们将通过MATLAB来实现这种滤波器。 二、LEE滤波器 2.1 LEE滤波器原理 LEE滤…

Linux Debian12将本地项目上传到码云(gitee)远程仓库

一、注册码云gitee账号 这个可以参考其他教程&#xff0c;本文不做介绍。 gitee官网&#xff1a;https://gitee.com/ 二、Linux Debian12安装git 如果Linux系统没有安装git&#xff0c;可以使用下面命令安装git sudo apt install git 三、gitee新建仓库 我这只做测试&…

关于el-date-picker组件修改输入框以及下拉框的样式

因为业务需求&#xff0c;从element plus直接拿过来的组件样式和整体风格不搭&#xff0c;所以要修改样式&#xff0c;直接deep修改根本不生效&#xff0c;最后才发现el-date-picker组件有一个popper-class属性&#xff0c;通过这个属性我们就能够修改下拉框的样式&#xff0c;…