REST API 安全设计指南
REST API 安全设计指南。REST 全称是 Representational State Transfer,它利用传统 Web 特点,提出一个既适于客户端应用又适于服务端的应用的、统一架构,极大程度上统一及简化了网站架构设计。
目前,在三种主流的 Web 服务实现方案中,REST 模式服务相比复杂的 SOAP 和 XML-RPC 来讲,更加简洁。越来越多的 web 服务使用 REST 设计并实现,但是它缺少安全特性。
REST API 简介
REST 全称是 Representational State Transfer,即表述性无状态传输。它无需 session,所以每次请求都得带上身份认证信息。Rest 既是基于 HTTP 协议的,也是无状态的。作为一种架构方式,它的安全特性需要自己实现,没有现成的。RESTful Web Services 概念的核心就是“资源”。 资源可以用 URI 来表示。客户端使用 HTTP 协议定义的方法来发送请求到这些 URIs,当然可能会导致这些被访问的”资源“状态的改变。HTTP 请求对应关系如下:
========== ===================== ======================== HTTP 方法 行为 示例 ========== ===================== ======================== GET 获取资源的信息 http://xx.com/api/orders GET 获取某个特定资源的信息 http://xx.com/api/orders/123 POST 创建新资源 http://xx.com/api/orders PUT 更新资源 http://xx.com/api/orders/123 DELETE 删除资源 http://xx.com/api/orders/123 ========== ====================== =======================
对于请求的数据,一般用 json 或者 xml 形式来表示,推荐使用 json。
身份认证
身份认证包含很多种,有 HTTP Basic、HTTP Digest、API KEY、Oauth 和 JWK 等方式,下面简单讲解下:
1.HTTP Basic
REST 由于是无状态的传输,所以每一次请求都得带上身份认证信息。身份认证的方式有很多种,第一种便是 HTTP basic,这种方式在客户端要求简单,在服务端实现也非常简单,只需简单配置 Apache 等 web 服务器即可实现,因此对于简单的服务来说,还是挺方便的。但是,这种方式安全性较低,就是简单的将用户名和密码 base64 编码放到header中。
base64 编码前:Basic admin:admin base64 编码后:Basic YWRtaW46YWRtaW4= 放到 Header 中:Authorization: Basic YWRtaW46YWRtaW4=
正因为是简单的 base64 编码存储,切记在这种方式下一定得注意使用 ssl,不然就是裸奔。 在某些产品中也是基于这种类似的方式,只是没有使用 Apache 的 basic 机制,而是自己写了认证框架,原理还是一样的,在一次请求中 base64 解码 Authorization 字段,再和认证信息做校验。很显然,这种方式有问题,认证信息相当于明文传输,另外也没有防暴力破解功能。
2.API KEY
API Key 就是经过用户身份认证后,服务端给客户端分配一个 API Key,类似: http://example.com/api?key=dfkaj134 。一般的处理流程如下:一个简单的设计示例
Client 端
Server 端
Client 端向服务端注册,服务端给客户端发送响应的api_key以及security_key,注意保存不要泄露,然后客户端根据 api_key、secrity_key、timestrap、rest_uri 采用 hmacsha256 算法得到一个 hash 值 sign,构造途中的 url 发送给服务端。
服务端收到该请求后,首先验证 api_key 是否存在,存在则获取该 api_key 的 security_key,接着验证 timestrap 是否超过时间限制,可依据系统成而定,这样就防止了部分重放攻击,途中的 rest_api 是从 url 获取的为 /rest/v1/interface/eth0,最后计算 sign 值,之后和 url 中的 sign 值做校验。这样的设计就防止了数据被篡改。通过这种 API Key 的设计方式加了时间戳防止部分重放,加了校验,防止数据被篡改,同时避免了传输用户名和密码,当然也会有一定的开销。
3.Oauth1.0a 或者 Oauth2
OAuth 协议适用于为外部应用授权访问本站资源的情况。其中的加密机制与 HTTP Digest 身份认证相比,安全性更高。使用和配置都比较复杂,这里暂不涉及。
4.JWT
JWT 是 JSON Web Token,用于发送可通过数字签名和认证的东西,它包含一个紧凑的、URL 安全的 JSON 对象,服务端可通过解析该值来验证是否有操作权限、是否过期等安全性检查。由于其紧凑的特点,可放在 url 中或者 HTTP Authorization 头中,具体算法如下图:
授权
身份认证后就是授权,根据不同身份,授予不同的访问权限。比如 admin 用户、普通用户、auditor 用户,它们是不同的身份。简单示例:
php $roles = array( 'ADMIN'=>array( 'permit'=>array('/^((\/system\/(clouds|device)$/'), // 允许访问哪些 URL 的正则表达式 'deny'=>array('/^(\/system\/audit)$/') // 禁止访问哪些 URL 的正则表达式 ), 'AUDIT'=>array( 'permit'=>array('/^(\/system\/audit)$/'),// 允许访问的 URL 正则表达式 'deny'=>array('/^((\/system\/(clouds|device).*)$/') ) );
上述是垂直权限的处理,如果遇到平行权限的问题,如用户 A 获取用户 B 的身份信息或者更改其他用户信息,对于这些敏感数据接口都需要加上对用户的判断,这一步一般都在具体的逻辑中实现。
URL 过滤
在进入逻辑处理前,加入对 URL 的参数过滤,如/site/{num}/policy 限定 num 位置为整数等,如果不是参数则直接返回非法参数,设定一个 url 清单,不在不在 url 清单中的请求直接拒绝,这样能防止开发中的 api 泄露。REST api 接口一般会用到 GET、POST、PUT、DELETE,未实现的方法则直接返回方法不允许,对于 POST、PUT 方法的数据采用 json 格式,并且在进入逻辑前验证是否 json,不合法则返回 json 格式错误。
重要功能加密传输
第一步推荐 SSL 加密传输,同时对于系统中的重要功能做加密传输,如证书、一些数据、配置的备份功能,同时还得确保具备相应的权限,这一步会在授权中涉及。
速率限制
请求速率限制,根据 api_key 或者用户来判断某段时间的请求次数,将该数据更新到内存数据库(redis、memcached),达到最大数即不接受该用户的请求,同时这样还可以利用到内存数据库 key 在特定时间自动过期的特性。
在 php 中可以使用 APC。Alternative PHP Cache (APC) 是一个开放自由的 PHP opcode 缓存。它的目标是提供一个自由、 开放和健全的框架用于缓存和优化 PHP 的中间代码。在返回时设置 X-Rate-Limit-Reset: 当前时间段剩余秒数,APC 的示例代码如下:
php Route::filter('api.limit', function() { $key = sprintf('api:%s', Auth::user()->api_key); // Create the key if it doesn't exist Cache::add($key, 0, 60); // Increment by 1 $count = Cache::increment($key); // Fail if hourly requests exceeded if ($count > Config::get('api.requests_per_hour')) { App::abort(403, 'Hourly request limit exceeded'); } });
错误处理
对于非法的、导致系统出错的等各种请求进行记录,还有一些重要操作,比如登录、注册等都通过日志接口输出展示。有一个统一的出错接口,对于 400 系列和 500 系列的错误都有相应的错误码和相关消息提示,如 401:未授权;403:已经鉴权,但是没有相应权限。
如不识别的 url:{"result":"Invalid URL!"},错误的请求参数{"result":"json format error"},不允许的方法:{"result":"Method Not Allowed"},非法参数等。上面所说的都是单状态码,同时还有多状态码,表示部分成功,部分字符非法等。
示例如下:
HTTP/1.1 207 Multi-Status Content-Type: application/json; charset="UTF-8" Content-Length: XXXX { "OPT_STATUS": 207 "DATA": { "IP_ADDRESS": [{ "INTERFACE": "eth0", "IP_LIST":[{ "IP": "192.168.1.1", "MASK": "255.255.0.0", "MULTI_STATUS": 200, "MULTI_RESULT": "created successfully" },{ "IP": "192.167.1.1", "MASK": "255.255.0.0", "MULTI_STATUS": 409, "MULTI_RESULT": "invalid parameter" }] }] },
重要 ID 不透明处理
在系统一些敏感功能上,比如,/user/1123 可获取 id=1123 用户的信息,为了防止字典遍历攻击,可对 id 进行 url62 或者 uuid 处理,这样处理的 id 是唯一的,并且还是字符安全的。
其他注意事项
1. 请求数据,对于 POST、DELETE 方法中的数据都采用 json 格式,当然不是说 rest 架构不支持 xml,由于 xml 不太好解析,对于大部分的应用,json 已经足够。近年来的趋势表明 json 越来越流行,并且 json 格式也不会有 xml 的一些安全问题。使用 json 格式目前能防止扫描器自动扫描。
2. 返回数据统一编码格式,统一返回类型,如 Content-Type: application/json; charset=”UTF-8″
3. 在逻辑实现中,json 解码之后进行参数验证或者转义操作,第一步 json 格式验证,第二步具体参数验证基本上能防止大部分的注入问题了。
4. 在传输过程中,采用 SSL 保证传输安全。
5. 存储安全,重要信息加密存储,如认证信息 hash 保存。
总之,尽量使用 SSL。
<< 上一篇
下一篇 >>