1. 什么是接口

接口简单来说就是服务器端用来返回给其他程序或者客户端数据的桥梁

2. 接口的作用

根据固定参数返回固定数据

3. API接口保障安全性原则

1.有调用者身份

2.请求的唯一性

3.请求的参数不能被篡改

4.请求的有效时间

4. 接口安全需求

1.最好必须启用HTTPS

2.signature签名

3.token登陆的唯一票据

4.验证时间戳

5.对要求安全性高的接口数据进行加密传输(aes+rsa)

5. signature签名

简而言之,签名设计的原则就是保证服务器所接收到的数据是自己的APP端传过来的,而不是其他人非法调用的,在APP端给签名加密时需要加上特有固定参数,服务器也是加上特有固定参数,从而来保证一对一的传输,每个接口都需要调用该签名验证方法

目的:

为了提高传参过程中,防止参数被恶意修改,在请求接口的时候加上sign可以有效防止参数被篡改

基本例子:

#接口

https://www.dong.com/api/product?&type=zl&p1=value1&p2=value2&p3=&sign=signValue

#第一步:

拼接参数字符串,除去sign参数本身和为空值的p3,

那么剩下的就是字符串type=zl&p1=value1&p2=value2,

然后按参数名字符升(降)序,

得到字符串p1=value1&p2=value2&type=zl

#第二步:

然后将参数名和值的字符串进行AES加密,

假设p1=value1&p2=value2&type=zl进行AES加密后的结果是abc123,

最终得到的字符串abc123就是参数sign的值signValue

#第三步:

在接口中我们会接收到参数名sign的参数值abc123,然后解密,

再与接口中参数拼接排序后进行比较,

如果不一样则说明参数的循序不一样,

参数的值就一定是被修改过了。

高级例子:

基本例子因为前端js暴露,

很容易被攻击人获取AES的加密方式,

因而有效防止参数被篡改就变得很弱。

所以,我们何不在AES的加密key进行RSA加密。

第一步:

我们先在客户端要产生一个random string(很重要,不能是单纯的string)

对其进行RSA加密,然后把加密后的内容发送给后端,

第二步:

我们把random string跟传递的参数+(时间戳13位数)进行AES加密,发送给后端

第三步:

后端进行解密,判断是否有改变传递的参数,

以及超过时间限制就不让访问,对sign进行cache缓存,

缓存中存在sign的就不让访问

RSA:非对称加密算法,内容越大,解密时间越长

AES:对称加密算法

代码例子:

/**
* [AesSecurity aes加密,支持PHP7.1]
*/
class AesSecurity
{
/**
* [encrypt aes加密]
* @param [type] $input [要加密的数据]
* @param [type] $key [加密key]
* @return [type] [加密后的数据]
*/
public static function encrypt($input, $key)
{
$data = openssl_encrypt($input, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
$data = base64_encode($data);
return $data;
}
/**
* [decrypt aes解密]
* @param [type] $sStr [要解密的数据]
* @param [type] $sKey [加密key]
* @return [type] [解密后的数据]
*/
public static function decrypt($sStr, $sKey)
{
$decrypted = openssl_decrypt(base64_decode($sStr), 'AES-128-ECB', $sKey, OPENSSL_RAW_DATA);
return $decrypted;
}
}
用openssl生成rsa密钥对(私钥/公钥):
openssl genrsa -out rsa_private_key.pem 2048
openssl rsa -pubout -in rsa_private_key.pem -out rsa_public_key.pem
RSA:
header('Content-Type: text/plain;charset=utf-8');
$data = 'phpbest';
echo '原始内容: '.$data."\n";
openssl_public_encrypt($data, $encrypted, file_get_contents(dirname(__FILE__).'/rsa_public_key.pem'));
echo '公钥加密: '.base64_encode($encrypted)."\n";
$encrypted = base64_decode('nMD7Yrx37U5AZRpXukingESUNYiSUHWThekrmRA0oD0=');
openssl_private_decrypt($encrypted, $decrypted, file_get_contents(dirname(__FILE__).'/rsa_private_key.pem'));
echo '私钥解密: '.$decrypted."\n";

6. token登陆的唯一票据

和PC登陆的session一样,作为用户进入的唯一票据

因为APP端没有和PC端一样的session机制,所以无法判断用户是否登陆,以及无法保持用户状态,所以就需要一种机制来实现session,这就是token的作用,token是用户登陆的唯一票据,只要APP传来的token和服务器端一致,就能证明你已经登陆

2、token设计时的种类:

(1)第三方登陆型:这种token形如微信的access_token,设计原理是按照OAuth2.0来的,其特点是定时刷新(比如两小时刷新),目的是因为数据源将登陆权限赋予第三方服务器时必须要控制其有效期和权限,要不然第三方服务器可以不经过用户同意,无限期从数据源服务器获取用户任意数据

(2)APP自用登陆型:这种token就是一般的APP用的token,因为不经过第三方,而是用户直接取数据源服务器数据,所以设计比较随意,只需要保证其token的唯一性就行

3、APP自用登陆型token实现步骤:

(1)数据库用户表添加token字段和time_out这个token过期时间点(不是时间段,即某个时间点)

(2)用户登陆时(注册时自动登陆也需要)生成一个token和过期时间存入表中

(3)在其他接口调用前,判断token是否正确,正确则继续,错误则让用户重新登陆

//token验证方法,db::是数据库操作类,

这里设置是token如果七天没被调用则需要重新登陆

(也就是说用户7天没有操作APP则需要重新登陆),

如果某个接口被调用,则会重新刷新过期时间

public static function checktokens($token, $table)
{
$res = db::getOneForFields($table, 'time_out', 'token1 = ?', array($token));
if (!empty($res))
{
if (time() - $res['time_out'] > 0)
{
return 90003; //token长时间未使用而过期,需重新登陆
}
$new_time_out = time() + 604800;//604800是七天
if (db::setWhere($table, array('time_out' => $new_time_out), 'token1 = ?', array($token)))
{
return 90001;
//token验证成功,time_out刷新成功,可以获取接口信息
}
}
return 90002; //token错误验证失败
}