1

Web アプリで機能する API の承認システムを実装しようとしています。署名検証と同様に 3 脚の OAuth を見てきましたが、OAuth にはあまり興味がありません。私がテストしている方法は、ここにあります。HMAC を使用して、Amazon 署名と同様にリクエストへの署名を承認します。ここで実際の例をまとめました。本当に空想的なものは何もありません。単なる概念実証です。

クライアント側はCryptoJsとJQueryを使用



   //Dummy credentials
    var username = 'username';
    var password = 'password';

    //first create the key and store it in memory for the duration of the app
    var KEY = CryptoJS.SHA512(username + "." + password).toString();
    var url = "http://127.0.0.1/whisppa/api";

    //setup the parameters that will be sent to the server
    var params = 
    {
        "user" : username,
        "requested_url" : CryptoJS.MD5(url).toString(),//hash the url to make it shorter
        "signature_version" : "1.0",
        "time" : 0
    }

    //get all parameters and sort them
    var props = [];
    for(var prop in params)
    {
        props.push(prop);
    }
    props.sort();

    //concatenate the parameters as a parameter string and set the time value
    var param_string = "";
    for(var prop in props)
    {
        prop = props[prop];
        if(prop == "time")
        {
            params.time = Math.round(new Date() / 1000);
        }

        param_string += prop + "=" + params[prop] + "&"; 
    }
    param_string = param_string.substring(0, param_string.length - 1);

    //generate the hmac of the request to be set in the header
    var hmac = CryptoJS.HmacSHA512(param_string, KEY).toString();

    //make the request
    $.ajax({
        type:"GET",
        beforeSend: function (request)
        {
            request.setRequestHeader("Auth-KEY", hmac);
        },
        url: url,
        data: "params=" + escape(JSON.stringify(params)),
        processData: false,
        success: function(msg) {
            $('body').html(msg);
        }
    }); 

サーバーには、スリムな php フレームワークと php 5.4 を使用します。

         


    //define the time before the app starts
    define('TIME', round(microtime(true)));

    $headers = getallheaders();

    //just make a few checks here to ensure necessary params are set
    if(!isset($_GET['params']) || !isset($headers['Auth-KEY']))
    {
        $app->halt(400);
    }
    //get the parameters from the get string
    $params = json_decode($_GET['params']);

    //make some more checks for important parameters
    if(!isset($params->time) || !isset($params->user))
    {
        $app->halt(400);
    }

    //get the parameters and sort them
    $properties = get_object_vars($params);
    ksort($properties);

    //concatenate the parameters as a parameter string
    $param_string = '';
    foreach($properties as $prop => $value)
    {
        $param_string .= $prop . '=' . $value . '&'; 
    }
    $param_string = substr($param_string, 0, strlen($param_string) - 1);

    //in reality, fetch the user from the database
    $password = 'password';

    //create the hash and then generate the HMAC
    $KEY = hash('SHA512', $params->user . '.' . $password);
    $Auth_KEY = hash_hmac('SHA512', $param_string, $KEY);

    //verify the request
    if($Auth_KEY == $headers['Auth-KEY'])
    {
        $app->halt(401);
    }

    //verify the time
    if(TIME - $params->time > 60)
    {
        $app->halt(408);
    } 

    //TODO: verify the requested url matches the current url

明らかに、これには問題があります。私が見ることができるのは

  1. ユーザーデータをサーバー側に格納する方法。プレーンテキストのパスワードを保存できません。ハッシュ化されたパスワードを保存できず、ユーザーのキーを保存すると問題が発生します。この問題を回避できないようです。

  2. アプリがメモリ内で実行されている間にキークライアント側を取得できないように保存することは可能ですか? 明らかに、firebug のようなツールや、chrome と firefox に付属の webdev ツールを使用すると、それを実現できます。しかし、コードで深くネストしたり、匿名関数でネストしたりすることは可能ですか?簡単に取得できません。実行中のアプリは私自身のものなので、これについてはあまり心配していません。

  3. リクエストに適用する適切なタイムアウトは?

  4. 見えないギラギラした穴はありますか?不注意による失明が原因かもしれません。

ありがとう。

編集

私が言ったように、これは単なる証拠です。要求メソッド/動詞もハッシュに追加されることを追加するのを忘れていました。

この回答は、パスワードの保存に関する回答を保持しているように見えますが、API キー/共有シークレットの使用方法が明確ではありません。

編集2

ここで私が目にするもう 1 つの問題は、ユーザーが他のコンシューマ アプリケーションでパスワードを入力できるようにすることです。良い解決策は、ある種の API キーまたは共有シークレットを使用することですが、これに関するアイデアはありますか?

4

1 に答える 1