如何設(shè)計(jì)簽名保護(hù)接口安全

參考: http://www.cnblogs.com/codelir/p/5327462.html

簽名的主要作用

  • 請(qǐng)求來源(身份)是否合法?
  • 請(qǐng)求的唯一性(不可重復(fù)請(qǐng)求)

步驟

  • 服務(wù)端給客戶端分配 app_id app_secret
  • 客戶端和服務(wù)端通過指定的算法生成簽名 sign
  • 客戶端每次請(qǐng)求都把 app_id 和生成好的 sign 放到請(qǐng)求參數(shù)中傳遞給服務(wù)端
  • 服務(wù)端拿出客戶端傳遞的 app_id 對(duì)應(yīng)的 app_secret 通過算法生成一個(gè) sign 和客戶端傳遞的 sign 對(duì)比

注意: app_secret 只是為了生成 sign 用的,請(qǐng)不要將 app_secret 放到請(qǐng)求參數(shù)中

關(guān)于算法

  • 將所有請(qǐng)求參數(shù)加入到算法中
  • 將時(shí)間戳加入到算法中(注意: js獲取的時(shí)間戳和PHP獲取的時(shí)間戳格式不一致)
  • app_secret 加入到算法中

舉個(gè)例子, 此處以 jquery 和 laravel 為例

使用 axios 的話,原理也是一樣的

  • 客戶端代碼
<script src="jquery.min.js"></script>
<script>
    $(function () {
        // 請(qǐng)求參數(shù)
        var params = {
            id: 1,
            app_id: 'xKYf550dzriIVeZbrcz2WpAMV0SOMCelpUcNfLDWm9vf1BdsT41uvqVE3PLH7lQx'
        };

        /**
         * 生成簽名加密算法
         * @param $params
         */
        function signGenerator($params) {
            // 獲取秘鑰和請(qǐng)求參數(shù)循環(huán)組成: secret:key=value&key=value&timestamp
            var secret = 'fw2FZjjmvKlpoByizWfScZbAluXdNwooABu93LEdKRV5ZOtJKrL7LEosb4IGBw4W';

            var sign = secret + ':';
            for (var key in params) {
                sign += key + '=' + $params[key] + '&';
            }

            // 獲取PHP格式的時(shí)間戳
            var timestamp = (new Date()).getTime() / 1000;
            console.log("客戶端生成的簽名:", window.btoa(sign + Math.floor(timestamp)));

            // window.btoa是js內(nèi)置的base64加密算法
            return window.btoa(sign + Math.floor(timestamp));
        }

        // 發(fā)送請(qǐng)求
        $.ajax({
            type: "GET",
            url: "https://www.example.com/api/test",
            data: params,
            beforeSend: function (request) {
                // 將簽名添加到請(qǐng)求頭中
                request.setRequestHeader("sign", signGenerator(params));
            },
            success: function (response) {
                console.log(JSON.stringify(response));
            }
        });
    });
</script>
  • 服務(wù)端代碼
    此處使用的是laravel的中間件
<?php

namespace App\Http\Middleware;

use Closure;

/**
 * 簽名驗(yàn)證中間件
 * Class SignVerify
 * @package App\Http\Middleware
 */
class SignVerify
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // 此處的 signList 是所有允許的 app_id 和 app_secret
        // 正常情況下應(yīng)該是存放到數(shù)據(jù)庫
        // 我寫死放到這里, 只是為了演示效果
        $signList = [
            [
                'app_id'     => 'xKYf550dzriIVeZbrcz2WpAMV0SOMCelpUcNfLDWm9vf1BdsT41uvqVE3PLH7lQx',
                'app_secret' => 'fw2FZjjmvKlpoByizWfScZbAluXdNwooABu93LEdKRV5ZOtJKrL7LEosb4IGBw4W'
            ],
            //...
            [
                'app_id'     => 'aaaaaaaaaa',
                'app_secret' => 'bbbbbbbbbb'
            ]
        ];

        // 獲取客戶端傳遞的 app_id 匹配服務(wù)端的 app_id對(duì)應(yīng)的 值
        $client_app_id = $request->input('app_id');
        $server_app_secret = null;
        foreach ($signList as $key => $value) {
            if ($value['app_id'] == $client_app_id) {
                $server_app_secret = $value;
                break;
            }
            continue;
        }

        if (is_null($server_app_secret)) {
            return 'Signature verification failed';
        }

        // 獲取 header 中客戶端傳遞的 sign 然后, 和服務(wù)端生成的sign對(duì)比
        $client_sign = $request->header('sign');

        // 服務(wù)端生成簽名(循環(huán)生成, 如果直接使用當(dāng)前時(shí)間戳可能有網(wǎng)絡(luò)延遲問題)
        $time   = time();
        $params = $request->all();
        $expire = 3; // 3內(nèi)秒鐘有效, 可以將這個(gè)放到配置文件中
        for ($i = 0; $i < $expire; $i++) {
            // 簽名正確就往后執(zhí)行
            if ($this->signGenerator($params, $server_app_secret, $time + $i) == $client_sign) {
                return $next($request);
            }
            continue;
        }
        return 'Signature verification failed';
    }

    /**
     * 生成簽名
     *
     * @param $params   請(qǐng)求參數(shù)
     * @param $secret   秘鑰
     * @param $time     時(shí)間戳
     * @return string
     */
    public function signGenerator($params, $secret, $timestamps)
    {
        $secret .= ':';
        foreach ($params as $key => $value) {
            $secret .= $key . '=' . '&';
        }

        // base64
        return base64_encode($secret . $timestamps);
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市澎埠,隨后出現(xiàn)的幾起案子始藕,更是在濱河造成了極大的恐慌,老刑警劉巖伍派,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拙已,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡倍踪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門扩借,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缤至,“玉大人,你說我怎么就攤上這事领斥。” “怎么了何恶?”我有些...
    開封第一講書人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵嚼黔,是天一觀的道長。 經(jīng)常有香客問我唬涧,道長划滋,這世上最難降的妖魔是什么粉怕? 我笑而不...
    開封第一講書人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任实牡,我火速辦了婚禮,結(jié)果婚禮上碗短,老公的妹妹穿的比我還像新娘。我一直安慰自己偎谁,他們只是感情好纲堵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铐望,像睡著了一般。 火紅的嫁衣襯著肌膚如雪正蛙。 梳的紋絲不亂的頭發(fā)上营曼,一...
    開封第一講書人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音锻全,去河邊找鬼。 笑死鳄厌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的部翘。 我是一名探鬼主播响委,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼赘风,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了邀窃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤鞍历,失蹤者是張志新(化名)和其女友劉穎肪虎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扇救,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年装畅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沧烈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚂夕,死狀恐怖汤锨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闲礼,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布慎菲,位于F島的核電站,受9級(jí)特大地震影響露该,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜解幼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一包警、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧害晦,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至笆呆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赠幕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來泰國打工竖慧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人圾旨。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓魏蔗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親莺治。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一床佳、作用 不使用SSL/TLS的HTTP通信榄审,就是不加密的通信。所有信息明文傳播搁进,帶來了三大風(fēng)險(xiǎn)。 (1)竊聽風(fēng)險(xiǎn)...
    XLsn0w閱讀 10,536評(píng)論 2 44
  • 必備品文檔:DocumentationAPI: API Reference視頻:Laracasts速查表:Lara...
    ethanzhang閱讀 5,746評(píng)論 0 68
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,104評(píng)論 1 32
  • 第一次參與放生篮撑,所以我想去匆瓜。 不過那種虔誠,我沒有體會(huì)到精髓驮吱,我不懂,甚至懷疑左冬。 魚兒放下去,我們?cè)诎渡弦恢?..
    莉莉安lilianan閱讀 211評(píng)論 0 0
  • 以前的我梅忌,從沒想過,自己一個(gè)人住牧氮,如今,可以坦然的面對(duì)瑰枫。 下班后,獨(dú)自走回來光坝,洗衣服,收拾東西盯另。上上網(wǎng),看視頻鸳惯,和...
    崔左岸煙逝閱讀 107評(píng)論 0 1