23.3  接口的安全控制规范

23.2节的示例实现了一个简单接口,但是这个接口此时是在“裸奔”的。因为这个接口所有人都可以请求,不仅我们的客户端可以正常访问数据,如果有人使用如fiddler、wireshark等抓包工具,就很容易获取这个API地址,可以随意地请求获取或篡改我们的数据,这很显然是不安全的。因此,在设计接口时必须加上安全控制这一环节。

23.3.1  API安全控制原则

由于Web API是基于互联网的应用,因此对安全性的要求远比在本地访问数据库严格得多。一般通用的做法是,采用参数加密签名方式传递,即在传递参数时,增加一个加密签名,在服务器端验证签名内容,防止被篡改。对一般的接口访问,只需要使用用户身份的token进行校验,只有检查通过才允许访问数据。API常用的安全控制原则有以下几种:

(1)使用用户名密码。这种方式比较简单,可以有效识别用户的身份(如用户信息、密码,或者相关的接口权限等)。验证成功后,返回相关的数据。

(2)使用安全签名。这种方式提交的数据,URL的连接参数是要经过一定规则的安全加密的,服务器收到数据后也经过同样的规则进行安全加密,确认数据没有被中途篡改后,再进行数据的修改处理。因此,我们可以为不同客户端,如Web、App等不同接入方式指定不同的密钥,但是密钥是双方约定的,并不在网络连接上传输,连接传输的一般是接入的“key”,服务器通过这个“key”来进行签名参数的加密对比。目前,微信后台的回调处理机制,采用的就是这种方法。

(3)公开的接口调用,不需要传入用户令牌,或者对参数进行加密签名,这种接口一般较少,只是提供一些很常规的数据显示而已。

23.3.2  API安全控制简单实现步骤

API的安全控制方法有很多,可以根据项目自身的情况定制一些方法,也可以借鉴一些大的平台处理接口的算法。本节通过一些简单的控制方式,来一步步实现API的安全访问控制。

1.增加时间戳参数

首先,我们在API的URL中添加一个时间戳参数,如“timestamp”,要求请求的客户端在请求接口的时候必须添加此参数。如果在请求的时候没有该参数,就不返回数据。另外,通过时间戳参数,也可以限制请求接口必须要在某个时间段内完成,即便有人发现了接口地址,也只能使用一段时间。加入时间戳参数后,请求接口的URL地址格式如下所示:

https://localhost/userapi.php?id=1&timestamp=1519552181

修改上例中的userclient.php文件,分别使用get()方法请求两次userapi.php接口,一次在URL加上“timestamp”参数,一次不加该参数。修改后代码片段如下所示:

同样地,修改userapi.php接口文件,判断在请求接口时,请求的URL中是否带有“timestamp”参数,并且限制该URL只能在5分钟内有效。修改后的代码片段如下所示:

运行的结果如图23-8所示。

图23-8  测试请求API的URL参数带有时间戳的结果

虽然我们实现了客户端软件在请求API时需要添加“timestamp”参数才能获取数据,但这样依然不能防止别人获取我们的数据,因为通过抓包工具依然是可以看到地址的,所以别人也可以添加 “timestamp”参数请求我们的接口。限时访问也只能瞒得过一般的程序员,稍微细心的程序员就会发现这个规律,他可以生成当前的时间戳,然后模拟参数发送请求来获取数据。

2. 增加签名参数

在发送API调用请求时,为了确保客户端应用与API服务器之间的安全通信,防止盗用URL、数据篡改等恶意攻击行为,在API验证规则中可以使用参数签名机制。过程是客户端应用在调用API之前,需要通过算法计算一个加密的签名,并追加到请求参数中,参数名可以为“sign”。API服务器在接收到请求时,使用同样的算法重新计算签名,并判断其值是否与应用传递来的“sign”参数值一致,以此判定当前API调用请求是否是被第三方伪造或篡改的。

签名的算法很多,本节模拟支付宝的签名算法。例如,制定一个规则,将所有URL的参数提取出来,然后根据参数名进行排序,再将排序后的数组拼接成字符串,最后对该字符串进行 md5或sha1加密(建议使用sha1)后得到“sign”。例如,当前我们的URL 如下所示:

http://localhost/userapi.php?id=1&timestamp=1527068730

(1)得到参数数组:['timestamp'=> 1527068730, 'id'=>100]。

(2)键名根据 ASCII 码进行排序后:['id'=>100,  'timestamp'=> 1527068730]。

(3)组合成字符串:id=100timestamp=1527068730。

(4)使用sha1()函数加密得到fd8cc3348652b9cbf2714689ab7ee9105da67cf4。

客户端和API服务器端签名的计算方法相同,计算后的请求URL地址如下所示:

http://localhost/userapi.php?id=1&timestamp=1527068730&sign=fd8cc3348652b9cbf2714689ab7ee9105da67cf4

继续修改上例中的userclient.php文件,再分别使用get()方法请求3次userapi.php接口,第一次没有添加“sign”参数,第二次使用错误的“sign”参数,第三次使用全部正确的参数。并通过上面的算法生成“sign”参数。修改后代码片段如下所示:

同样地,修改userapi.php接口文件,判断在请求接口时,请求的URL是否带有“sign”参数,和客户端使用相同的算法计算签名,并和URL中接收到的客户端“sign”参数进行匹配,如果相同则返回数据,如果不同则可能被篡改,返回错误消息。修改后代码片段如下所示:

运行的结果如图23-9所示:

图23-9  测试请求API的URL参数带有sign的结果

通过签名参数,能大大提高接口的安全性,其他人不能随意地请求接口。虽然有人也可以抓取接口地址,但是也只能获取这一条数据,不能请求别的数据。例如,有人抓取了上例中的这个接口地址,它只能获取ID为1的文章。并且5分钟的时间内,它无法通过修改参数来获取ID为100的文章,因为一旦参数变化,“sign”参数校验就会失败。支付宝接口就是这样做的,避免交易金额随便被更改。

3. 引入token

虽然通过添加“时间戳”和“签名”参数,接口相对比较安全了,但是还是有隐患,如果别人知道了加密规则(当然规则可以变化,如倒序排序,或双层sha1加密等),采用相同的规则加密参数得到“sign”,就能接着获取其他的数据了。所以,需要再引入另一个元素“token”,它是一个约定值,相当于“暗号”,其实就是只有客户端和服务器端知道的一个随机字符串。当然这个“token”字符串在客户端用户那里是不可见的,如果客户端是App,代码是编译过的,客户端使用PHP程序,在服务器上不会传给用户。引入“token”只需要将这个随机的字符串加入sign 的计算中,就能再次提高接口的安全性。 继续修改上例中的userclient.php文件,引入“token”进入签名运算。修改后代码片段如下所示:

继续修改上例中的userapi.php文件,同样引入相同内容的“token”进入签名运算中。修改后代码片段如下所示:

再次运行后,和上例运行得到的结果相同。到此为止,我们的接口已经变得比较的安全了,其他人想要请求我们的接口,就必须知道我们的签名加密规则和随机的“token”字符串,这个可能性就太低了。

《细说PHP》第四版 样章 第23章 自定义PHP接口规范 5的更多相关文章

  1. 《细说PHP》第四版 样章 第二章 PHP的应用与发展 1

    <细说PHP>第四版 样章 第二章 PHP的应用与发展 1 学习任何编程语言之前,先了解一下它的应用与发展是很有必要的.从Web开发的历史看来,PHP.Python和Ruby几乎是同时出现 ...

  2. 《java编程思想(第四版)》第一二章学习笔记

    目录 一.Introduction 1.抽象过程 2.面向对象语言(包括Java)的五个基本特性 3.每个对象都提供服务 4.public.private.protected三者的区别 5.Java的 ...

  3. 《细说PHP》 第四版 样章 第二章 PHP的应用与发展 5

    2.5  如何学习PHP PHP以其简单易学的特点,以及敏捷开发的优势,从一个几乎不被人知的开源项目,慢慢成长为技术人员首选的动态Web设计工具,与其他语言相比,PHP表现得更好.更快.更简单易学.尽 ...

  4. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 11

    23.6  使用第三方接口服务实例 接供服务的第三方接口平台有很多,现在的项目中也经常用到一些第三方接口,如支付宝.微信.短信.邮件接口等,我们需要借助第三方的能力来实现产品的某些功能.如果自己已经掌 ...

  5. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 9

    23.5.3  WebAPI框架应用 程序框架其实就是一个半成品项目,在应用框架时,核心的服务程序只应用,不需要改动.当然如果有必要,也可以根据项目的需要对框架进行二次开发.本节内容主要基于我们的框架 ...

  6. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 8

    23.5.2  架构详解 本例的实现最重要的就是服务层的设计,有两个配置文件config.php和api.php,其中文件config.php是全局的配置文件,用于整个程序全局需要的参数设置.可以根据 ...

  7. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 6

    23.4  API的设计原则和规范 API是服务提供方和使用方之间对接的通道,前面我们设计的一些简单API的例子,基本上比较随意,没有使用任何规范.设想一下,每个平台都可能存在大量的API,如果API ...

  8. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 3

    23.2  接口实现的基础 大家都很了解函数在本地应用,通过名称调用函数执行,并通过传递不同参数,函数有不同执行,执行后给调用者返回结果.如果把一个函数做成一个接口远程访问,也需要这几个步骤.使用HT ...

  9. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 1

    如今的项目开发中,接口是很普遍的应用技术.现在好多项目组都单独设有接口开发人员.像腾讯.微博.淘宝等开放平台,其所谓的开放,就是提供一些可调用的接口,用于获取相关的信息.例如,微信用户基本信息.淘宝店 ...

  10. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 12

    18.9  管理表books实例 在Web项目中,几乎所有模块都要和数据表打交道,而对表的管理无非就是增.删.改.查等操作,所以熟练掌握对表进行管理的这些常见操作是十分有必的.本例为了能更好地展示PD ...

随机推荐

  1. Django使用MySQL数据库的流程

    Django使用MySQL数据库的流程 手动创建一个MySQL数据库 配置数据库 ENGINE MySQL NAME 数据库的名字 HOST ip PORT 3306 USER 用户名 PASSWOR ...

  2. ORM映射(对象关系映射)

    ORM映射(对象关系映射)分创建表和操作表两个部分创建单表创建关联表(foreignKey) 一对一 一对多(重点) 多对多(重点) 创建表后加str方法把打印的地址转换成对应字符表的操作(增删改查) ...

  3. JSON.parse和JSON.stringify方法

    1.JSON.parse(“要转换的数据”) 2.JSON.stringify(“要转化的数据”) 3.首先,两个方法的用法是有差别的: ①.JSON.stringify是从一个对象中解析出字符串 ② ...

  4. ElementPath

    ElementTree库附带了一个简单的类似XPath的路径语言ElementPath主要区别在于,可以在ElementPath表达式中使用{namespace}标记符号但是,诸如值比较和函数之类的高 ...

  5. python访问kafka

    操作系统 : CentOS7.3.1611_x64 Python 版本 : 3.6.8 kafka 版本 : 2.3.1 本文记录python访问kafka的简单使用,是入门教程,高阶读者请直接忽略. ...

  6. sql书写和执行顺序

    (8)SELECT (9)DISTINCT<select_list> (1)FROM <left_table> (3)<join_type> JOIN<rig ...

  7. javaWeb综合案例

    商城案例 分模块:用户模块→ 分类模块 → 商品模块→购物车模块(最难)→ 订单模块 后台模块(往前台的数据的增删改查) 今日任务: 1用户注册 a注册完成 b给注册人发邮件 2用户激活 a 去邮箱激 ...

  8. netcore3.0使用Session

    首先需要明确一点,netcore使用session不能直接使用,必须引用nuget包并做注册之后才能使用. 例如下面的例子,若未注册session服务会报 HttpContext.Session.Se ...

  9. SSM框架之Mybatis(7)延迟加载、缓存及注解

    Mybatis(7)延迟加载.缓存及注解 1.延迟加载 延迟加载: 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据.延迟加载也称懒加载. **好处:**先从单表查询,需要时再从关联表去关 ...

  10. 解决html导出pdf中文乱码问题的正确姿势

    简介 本文使用jspdf 1.5.3版.GitHub地址:https://github.com/MrRio/jsPDF jspdf是歪果仁开发的,因此在一开始就没想过支持非英文以外的文字,这就导致了非 ...