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
明らかに、これには問題があります。私が見ることができるのは
ユーザーデータをサーバー側に格納する方法。プレーンテキストのパスワードを保存できません。ハッシュ化されたパスワードを保存できず、ユーザーのキーを保存すると問題が発生します。この問題を回避できないようです。
アプリがメモリ内で実行されている間にキークライアント側を取得できないように保存することは可能ですか? 明らかに、firebug のようなツールや、chrome と firefox に付属の webdev ツールを使用すると、それを実現できます。しかし、コードで深くネストしたり、匿名関数でネストしたりすることは可能ですか?簡単に取得できません。実行中のアプリは私自身のものなので、これについてはあまり心配していません。
リクエストに適用する適切なタイムアウトは?
見えないギラギラした穴はありますか?不注意による失明が原因かもしれません。
ありがとう。
編集
私が言ったように、これは単なる証拠です。要求メソッド/動詞もハッシュに追加されることを追加するのを忘れていました。
この回答は、パスワードの保存に関する回答を保持しているように見えますが、API キー/共有シークレットの使用方法が明確ではありません。
編集2
ここで私が目にするもう 1 つの問題は、ユーザーが他のコンシューマ アプリケーションでパスワードを入力できるようにすることです。良い解決策は、ある種の API キーまたは共有シークレットを使用することですが、これに関するアイデアはありますか?