API接口安全增強設計方法

前面兩篇相關文章:php

Web Api 內部數據思考 和 利用http緩存優化 Apihtml

Web Api 端點設計 與 Oauthapi

 

1.開放的接口數組

這樣的接口咱們每天都在接觸,例如查快遞,你查天氣預報,你查飛機,火車班次等,這些都是有公共的接口。
緩存

例如騰訊的開放平臺:安全

<?php

/**
 * OpenAPI V3 SDK 示例代碼,適用於大部分OpenAPI。若是是上傳文件類OpenAPI,請參考本SDK包中的「Test_UploadFile.php」文件中的示例代碼。
 *
 * @version 3.0.4
 * @author open.qq.com
 * @copyright © 2012, Tencent Corporation. All rights reserved.
 * @History:
 *               3.0.4 | coolinchen | 2012-09-07 10:20:12 | initialization
 */


require_once 'OpenApiV3.php';

// 應用基本信息
$appid = 100657839;
$appkey = 'b96b85196a04ff2ef08707f43979db15';

// OpenAPI的服務器IP 
// 最新的API服務器地址請參考wiki文檔: http://wiki.open.qq.com/wiki/API3.0%E6%96%87%E6%A1%A3 
$server_name = '119.147.19.43';


// 用戶的OpenID/OpenKey
$openid = 'E098C1E975A2459E534B48FB3224CFB6';
$openkey = '05219DB6D7C04CA0B3F01A51D32635E3';

// 所要訪問的平臺, pf的其餘取值參考wiki文檔: http://wiki.open.qq.com/wiki/API3.0%E6%96%87%E6%A1%A3 
$pf = 'qzone';


$sdk = new OpenApiV3($appid, $appkey);
$sdk->setServerName($server_name);

$ret = get_user_info($sdk, $openid, $openkey, $pf);
print_r("===========================\n");
print_r($ret);

/**
 * 獲取好友資料
 *
 * @param object $sdk OpenApiV3 Object
 * @param string $openid openid
 * @param string $openkey openkey
 * @param string $pf 平臺
 * @return array 好友資料數組
 */
function get_user_info($sdk, $openid, $openkey, $pf)
{
    $params = array(
        'openid' => $openid,
        'openkey' => $openkey,
        'pf' => $pf,
    );
    
    $script_name = '/v3/user/get_info';
    return $sdk->api($script_name, $params,'post');
}

 

2.接口參數加密(基礎加密)服務器

驗證彼此約定好的key,驗證經過,便可調用api。app

  /**
      * 簽名驗證
      * 
      * @version 2017-08-14 
      */    
     function checkSign( $dataAry )
     {
        if(GAME_KEY == $dataAry['sign']) {   //GAME_KEY爲 項目中的key , sign 爲傳遞過來的簽名,簡單的驗證是否對等,便經過
            return true;
        }
        
        return false;
     }

   //驗證簽名 不經過直接返回
     if(!checkSign($paramsAry)) {
        $retCode = 105;
        echo makeReturn($paramsAry,$retCode);
        exit();
     }

 

這樣子作的缺點以下:post

1 若是不當心把key泄露,那麼很容易被他人調用接口優化

2 開發者常常把sign附帶於URL中進行請求,這樣子容易被獲取到URL請求參數,進而拿到sign

增強方法:

1 把URL請求參數進行base64爲加密後再請求,或其餘加密方式,將請求參數進行加密後,再請求

2 限制可請求接口的ip 【通常用於充值等高防範的接口中】

 

3.變換的接口參數加密【較爲安全】

key 不會永遠都是安全的,也有可能被泄露,那麼咱們能夠怎麼作呢?咱們能夠生成變換的簽名sign,且輔助其餘參數進行排序變化加密

例如對全部的參數(加上時間戳),按照首字母進行排序後,進行md5或sha加密,這時候每次生成的sign都是變化的,其餘人即便拿到了key,若是不知道排序方式與加密方式,那麼是沒法算出sign的。

例如:

/**
     * 生成簽名
     * 
     * @param $params 參數列表 數組 array('param1'=>'value1','param2'=>'value3',...)
     * @param $key 密鑰 默認從配置文件取(GAME_KEY)
     */
    function genSign($params,$key='')
    {
        if($key == '') {
            $key = GAME_KEY;
        }    
        //過濾空值
        $paraFilter = array();
        while (list ($k, $v) = each ($params)) {
            if($k == 'sign' || $v == '')continue;
            else    $paraFilter[$k] = $params[$k];
        }
        
        //升序排列數
        ksort($paraFilter);
        reset($paraFilter);
        
        //生成參數字符串
        $paramsString  = "";
        while (list ($k, $v) = each ($paraFilter)) {
            $paramsString.=$k."=".$v."&";
        }
        //去掉最後一個&字符
        $paramsString = substr($paramsString,0,count($paramsString)-2);        
        //若是存在轉義字符,那麼去掉轉義
        if(get_magic_quotes_gpc()){$paramsString = stripslashes($paramsString);}
        
        //加上key,進行md5
        $paramsString .='&key='.$key;
        $sign = md5($paramsString);
        
        return $sign;
    }

可增強點:

1 尾部帶上雙方約定好的key,再進行md5與sha同時加密

2 url參數同時也要進行base64或者其餘加密,例如最後能看到的請求url爲:

http://www.example.com/pay.php?data = SDDLKFKDKFLDHOIDHSALFSALDJALDSSALKJLDJSALDMSA

3 不要明顯的提示缺乏什麼參數,並且準確的使用錯誤碼。

 

4 . 變換的接口參數加密 + ip驗證【非必須】 + 時效性檢查 + https 【安全性高】

只有特定的ip,才容許請求這個接口:

/**
 * 獲取客戶端IP地址
 *
 */
function getIp()
{
    $realip='';
    if (isset($_SERVER)){
        if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
            $realip = $_SERVER["HTTP_X_FORWARDED_FOR"];
        } else if (isset($_SERVER["HTTP_CLIENT_IP"])) {
            $realip = $_SERVER["HTTP_CLIENT_IP"];
        } else {
            $realip = $_SERVER["REMOTE_ADDR"];
        }
    } else {
        if (getenv("HTTP_X_FORWARDED_FOR")){
            $realip = getenv("HTTP_X_FORWARDED_FOR");
        } else if (getenv("HTTP_CLIENT_IP")) {
            $realip = getenv("HTTP_CLIENT_IP");
        } else {
            $realip = getenv("REMOTE_ADDR");
        }
    }
     
    return $realip;
}

if(getIp() != '特定的ip'){
  echo makeReturn($paramsAry,$retCode);
    exit();
}

進行時效性檢查:

    /**
     * 檢查是否url過時
     * @param int $ts 時間戳
     * @param int $limitTime 有效期:默認爲5分鐘
     * @return string or boolean 成功且對方有返回值則返回
     */
    function checkTime($ts, $limitTime='300')  // 5分鐘的有效期
    {
        $sencond = abs(time()-$ts);
        if ($sencond<=$limitTime)
        {
            return true;
        }
        return false;
    }

HTTPS這塊相對比較麻煩,咱們項目所用的是免費版本的,因此常常彈出驗證框。後面終於買了個收費版本,用起來挺好。

4 . 總結

在安全的同時,要根據業務進行接口的調整,例如:

1 API版本的迭代規範,版本分支(例手遊項目接口迭代比較重要),開發規範,模塊管理(例如頁遊對接平臺較多,模塊管理比較重要)。

2 客戶端與服務端的雙向驗證,不少時候大部分都是服務端驗證,而後返回錯誤碼,客戶端進行錯誤碼驗證是否正確,某些狀況下,咱們也能夠服務端驗證經過後,客戶端同時也進行驗證服務端返回的內容。

3 能夠在限定ip下,請求惟一入口api來獲取其餘接口的key,這也是一個不錯的辦法。key能夠隨便改變且不用通知接入方。

相關文章
相關標籤/搜索