1.1. 如何有效的防止API重放攻击

基于 TOTP [Time-Based One-Time Password Algorithm]

表示基于时间戳算法的一次性密码。

1.1.1. 需要同步服务器时间

  • 基于时间戳的 容错
  • reqID 每个 tk 下只能使用一次 保证API无法重放
  • 容错时间 要小于 ck 的过期时间

1.2. 包

spomky-labs/otphp

1.3. 简单例子

public function SignCheck($appid, $appSecret, $reqid, $tk, $sign)
    {
        $S = md5(base64_encode($appid . $appSecret . $reqid . $tk));
        if ($sign === $S) {
            return true;
        }
        return false;
    }

    public function ToTpAuth($appid, $appSecret, $reqid, $tk)
    {
        $cK = "Totp:channle_{$appid}:{$tk}:{$reqid}"; //设置失败 说明reqid使用过 防止重放
        if (\RedisDB::setnx($cK, 1)) {
            \RedisDB::expire($cK, 60); //设置过期时间
            $appSecret = Base32::encodeUpper("{$appSecret}", "=");
            $totp      = TOTP::create($appSecret, 50, 'sha1', 12); //容错时间
            return $totp->verify($tk,time());
        }
        return false;
    }

        $appid = $request->input('appid');
        $reqid = $request->input('reqid');
        $tk    = $request->input('tk');
        $sign  = $request->input('sign');

        if (empty($appid) || empty($reqid) || empty($tk) || empty($sign)) 
        {
            return Functions::getMessageBody("Err.", [], 222222);
        }
        $ChannleModel = new ChannleModel();
        $Info         = $ChannleModel->where('app_id', $appid)->where('status', 1)->first();
        // TODO 查询 渠道信息  获取密钥 简单写 可以改成从redis 获取配置 
            if (empty($Info)) {
                return Functions::getMessageBody("Err.", [], 333333);
            }
            if (!$this->SignCheck($appid, $Info->app_secret, $reqid, $tk, $sign)) {
                return Functions::getMessageBody("Sign Err.", [], 333334);
            }
            if (!$this->ToTpAuth($appid, $Info->app_secret, $reqid, $tk)) {
                return Functions::getMessageBody("Sign Err.", [], 333335);
            }

results matching ""

    No results matching ""