API接口安全性设计

来源:互联网 发布:ubuntu samba图形界面 编辑:程序博客网 时间:2024/04/28 21:29

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


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


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


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


整个流程如下:

1、客户端通过用户名密码登录服务器并获取Token

2、客户端生成时间戳timestamp,并将timestamp作为其中一个参数

3、客户端将所有的参数,包括Token和timestamp按照自己的算法进行排序加密得到签名sign

4、将token、timestamp和sign作为请求时必须携带的参数加在每个请求的URL后边(http://url/request?token=123&timestamp=123&sign=123123123)

5、服务端写一个过滤器对token、timestamp和sign进行验证,只有三个参数都正确且在规定时间内,本次请求才有效



在以上三中机制的保护下

如果黑客劫持了请求,并对请求中的参数进行了修改,签名就无法通过;

如果黑客使用已经劫持的URL进行DOS攻击,服务器则会因为缓存服务器中已经存在签名而拒绝服务,所以DOS攻击也是不可能的;

如果黑客隔一段时间进行一次DOS攻击(假如这个时间大于签名在缓存服务器中的缓存时长),则会因为时间戳超时而无法完成请求,这就是为什么签名的缓存时长要跟时间戳的超时时长一样。

如果签名算法和用户名密码都暴露了,你懂的。。。。

示例代码

//API基础控制层

useThink\Controller;

classBaseController extends Controller

{

    protected$access_token;

    privatestatic $secret = "";


    publicfunction __construct()

   {

      parent::__construct();

       self::checkEncrypt()? :self::response(-32003);

       self::checkIsPost()?:self::response(-32009);

   }

  

    publicstatic function checkEncrypt(){

       $request_data['access_token']= isset($_REQUEST['access_token']) &&trim($_REQUEST['access_token']) ? trim($_REQUEST['access_token']) :"";

       $request_data['time'] =isset($_REQUEST['time']) && trim($_REQUEST['time']) ?intval($_REQUEST['time']) : 0;

       if($request_data['access_token'] !=md5(self::$secret.$request_data['time']) ){

          $flag = false;

       }

       if(!$request_data['access_token'] ||!$request_data['time']){

          $flag = false;

       }else{

          $flag = ture;

       }

        return$flag;

   }



  

    publicstatic function checkValidTime(){

       $request_data['time'] =isset($_REQUEST['time']) && trim($_REQUEST['time']) ?intval($_REQUEST['time']) : 0;

       $flag =ture;

       if( $request_data['time'] -time() > 2 || $request_data['time'] - time() < 0){//每次接口 2秒有效

          $flag = false;

       }

       return$flag;

   }

    publicstatic function check($request_data){

      self::checkPara($request_data)?:self::response(-32001);

   }


  

    protectedfunction checkIsPost()

   {

       if (IS_POST){

          return true;

       } else {

          return false;

       }

   }


  

    staticfunction timediff($begin_time, $end_time)

   {

       if ($begin_time <$end_time) {

          $starttime = $begin_time;

          $endtime = $end_time;

       } else {

          $starttime = $end_time;

          $endtime = $begin_time;

       }

       $timediff = $endtime -$starttime;

       $days = intval($timediff /86400);

       $remain = $timediff %86400;

       $hours = intval($remain /3600);

       $remain = $remain %3600;

       $mins = intval($remain /60);

       $secs = $remain %60;

       returnarray(

          "day" => $days,

          "hour" => $hours,

          "min" => $mins,

          "sec" => $secs

       );

   }

  

    publicstatic function checkPara($request_data){

       $flag =true;

       foreach ($request_data as$key => $value) {

          if(!isset($value)){

              $flag =false;

          }

       }

      //var_dump($request_data);

       return$flag;

   }

    publicstatic functionresponse($code,$data=null,$message=null){

       $json_array["code"] =intval($code);

       $json_array["message"] =$message? $message : self::$code[$code];

       $json_array["time"] =time();

       if($data){

          $json_array["data"] = $data;

       }

       echojson_encode($json_array);

       exit;

   }

}

原创粉丝点击