6

私は CakePHP アプリケーション用の簡単なテスト API を作成しました。この API を使用すると、ユーザーはモバイル デバイス (または任意のデバイス) からログインして、JSON 応答を取得できます。この API は、PhoneGap で構築されたモバイル アプリに使用できます。

ログイン方法は次のようになります。

public function login()
{
    if($this->request->is('post'))
    {
        // Use custom method in Model to find record with password params
        $findUser = $this->User->findUser(
            $_POST['username_or_email'],
            AuthComponent::password($_POST['password'])
        );

        // If a user exists and matches params
        if($findUser)
        {                           
            $this->User->id = $findUser['User']['id'];

            $this->autoRender = false;
            $this->response->type('json');
            $this->response->body(json_encode(array('authenticated'=>true,'message'=>__('You have been logged in successfully'))));
        }
        else
        {
            $this->autoRender = false;
            $this->response->type('json');
            $this->response->body(json_encode(array('authenticated'=>false,'message'=>__('Username or password is incorrect'))));
        }

    }
    else
    {
        $this->autoRender = false;
        $this->response->type('json');
        $this->response->body(json_encode(array('message'=>'GET request not allowed!')));
    }
}

モバイル デバイス (または任意の API ユーザー) は、ログインの詳細を送信できます。その後、認証済みの true または false として JSON として要求を取得します。このブール値は、ユーザー アクセスを許可するために使用されるのではなく、モバイル アプリに特定の画面を表示できるかどうかを伝え、データのみを取得するか、セッションが存在する場合にデータを送信できます。

前述のように、実際にはデバイス上の API 自体にもログインしているため、(そのデバイスから) Web サイトに直接アクセスすると、セッションが発生し、JSON に対して同じ応答が表示されます。

したがって、基本的に、ユーザーは、サーバーと通信しているデバイスでのセッションの間、ログインしたままになります。これは、この例のようにセッションがある場合に、リクエストごとに渡す必要があるトークンとは異なります。

さて、質問は...

  1. 上記のようなセッションでユーザーが「実際に」API にログインするのは悪い習慣ですか? ダイレクト Web ルートと同じロジックを使用しているため、デバイスの認証を処理する最も安全な方法のようです。

  2. 私が実装した代わりに、いくつかの API がアクセス トークンを使用しているのを見てきました (ユーザーはブール値の代わりにトークンを取得し、セッションは作成されません)。しかし、私が知る限り、リクエストが行われるたびにユーザー レコードに対してアクセス トークンを確認する必要があるため、これはより多くの作業のように思えます。

4

4 に答える 4

25

編集
明確にするために、私はRESTのサポーターではなく、RESTful/RESTのようなサービスのサポーターです. インターネット上のすべての API を見ても、実際に 1 つの標準に固執しているものはほとんどありません。どのスキームを選択するかは、特定の問題空間によって異なります。安全を確保し、直感的なデザインを選択するようにしてください (つまり、「犬」に関する情報を返す場合、サービスに「猫」という名前を付けないでください)
編集を終了

RESTful API では、何らかの形式のセッション/トークン化スキームを管理することをお勧めします。本当に理想的な (少なくとも私の意見では、この問題については多くの考え方があります) セットアップには、ローリング トークンが含まれます。

API のセキュリティに関心がある場合は、アクセス許可をデータベース レイヤーから管理する必要があります。はい、これはボトルネックを作成しますが、それは実際には良いことです。クライアントのトークンを検証するために毎回データベースにアクセスする必要があるため、プロセス全体に余分なステップが追加されます。これにより API の速度が低下しますが、これは安全なシステムでは望ましいことです。悪意のある個人が 1 秒間に 3000 回も API をヒットできるようにしたくないので、彼らのリクエストを (ある程度) かなりの数秒間ハングさせたいと考えています。

これは、 MD5ハッシュ アルゴリズムに似ています。それらの多くは、間にランダムな一時停止を挟んで、数百回ハッシュを再計算します。これにより、悪意のあるクライアントがパスワードをブルート フォースしようとするのを防ぐことができます (パスワード文字列の各バリエーションをテストする時間が長くなるため)。同じことが API にも当てはまります。

もう1つの利点は、悪意のあるユーザーが何度も何度もログインしようとしている場合、それらをデータベースレイヤーから管理している場合、そのユーザーのIPアドレス/ユーザー名/持っているものに赤いフラグを立てることができるということです。ステップ 1 で要求をドロップします。

とにかく、提案されたプロセスの場合 (ローリングトークンを使用すると、やり過ぎと思われる場合はこれの一部を切り取ることができますが、これは非常に安全です):

  1. ユーザーは「ログイン」サービスにアクセスします。これにはユーザー名とパスワードが必要で、プライベート アクセス トークンとパブリック リクエスト トークンの 2 つのトークンが返されます (サーバーはこれらのトークンをデータベースに保存します)。
  2. クライアントはこれらのトークンを安全な場所に保管します
  3. ユーザーが別のエンドポイントにアクセスしてデータをプッシュ/プルする
    • リクエストにタイムスタンプが含まれています
    • リクエストにパブリック リクエスト トークンが含まれている
    • リクエストにアクセス トークンが含まれている => このトークンは、プライベート アクセス トークン文字列の末尾にタイムスタンプ文字列を連結した結果の文字列の MD5 ハッシュである必要があります
  4. サーバーはパブリック リクエスト トークンを取得し、それを使用して、保存されているプラ​​イベート アクセス トークンを検索します。
    • サーバーはそのプライベート アクセス トークンを取得し、タイムスタンプ文字列を連結してから、この文字列の MD5 を取得します。
    • 新しいアクセス トークンが、クライアントがサーバーに送信したものと一致する場合、HURRAY、このクライアントは検証されるので、データをプッシュ/プルします
  5. (オプション) サーバーはリクエストごとに新しいトークンを生成し、それらをクライアントに返します。このようにして、すべてのトランザクションが古いトークンを無効にし、なんらかの中間者攻撃が発生した場合、VALID ユーザーがすでに要求を完了している場合、悪意のあるユーザーは無効なトークンを持ち、いじり始めることができなくなります。あなたのAPI。このスキームは、悪意のあるユーザーがサーバーとクライアント間の単一の通信を傍受することを期待できず、それでもシステムにアクセスできるようにしようとします。その場合、REAL ユーザーは無効化されたトークンをすぐに取得する必要があります。これにより、API クライアントが「ログイン」サービスを再びヒットし、新しい有効なトークンを取得するようになります。これにより、悪意のあるユーザーが再びシステムから追い出されます。

このスキームは 100% 安全ではありません。ユーザー アクセス システムは決して安全ではありません。トークンに有効期限を追加することで、より安全にすることができます。このスキームには、ユーザー/トークンに特定のアクセス許可を割り当てることができるという追加の利点もあります (つまり、読み取り専用アクセス、特定のエンドポイントのみが表示されるなど)。

これはあなたができる唯一の方法ではありません。他の認証スキームを調べて、それぞれから必要なものを取得します(OAUTHは開始するのに適した場所です。次に、Facebook / Twitter / Instagramを調べます)

于 2013-02-26T15:38:39.850 に答える
3

Swayokが最後に提案したように、ログインパスのペアではなく、アプリを毎回ログインさせます。ログインすると、サーバーはトークンを生成し、それをクライアントに返します。クライアントは、リクエストを行うたびにこのトークンを使用します。リクエストごとに、サーバーはトークンが有効かどうかを確認し、有効な場合はリクエストを実行します。

これは、サーバー側のフレームワークが内部でセッションを管理し、これらのトークンが時々期限切れになるという点でセッションが機能する方法と非常に似ています。ただし、Swayok が正しく指摘したように、主に RESTful API には状態がないため、セッションは必要ありません。ユーザーに関するユーザー固有のデータを保存せずに同じユーティリティを取得し、リクエストごとにユーザーをログインさせます。

これに関する優れた記事はこちらです。または、Facebook Graph API エクスプローラーを試して実際の動作を確認することもできます。

于 2013-02-26T00:23:47.880 に答える
2

Restful API は、セッションの使用とシステム状態の保存をまったく制限します。各リクエストは、ユーザーにログインする必要があります。アクセス トークンは優れていますが、追加の処理も必要です。最も簡単な方法は、HTTP Basic Auth
("Authorization" HTTP ヘッダー) を介して認証データを送信する ことです。 APIに。 サーバー側:


$username = env('PHP_AUTH_USER');  
$password = env('PHP_AUTH_PW'); 

そして、ApiAppController->beforeFilter() でこのデータを使用してユーザー ログインを処理します。

于 2013-02-20T17:20:43.880 に答える
0

あなたの質問に答えるために

  1. アプリを閉じるときにセッションを閉じ、必要に応じて再作成する限り、悪い習慣ではありません。これは、ブラウザにログインした場合と同じであり、ログアウトする機能がありますが、アプリでも同じことが利用できるはずです。そうでない場合、アプリを閉じても実際にはセッションを終了していない可能性があります。アプリを閉じたときに自動チェックをログアウトするように依頼することで、さまざまな方法でこれを処理できます
  2. トークンは上記を行うための拡張された方法ですが、送信時のトークンの安全性を考慮する必要があり、サーバーは要求ごとにトークンを検証する必要があります。時間やお金の制約があり、セッションスタイルが将来アプリケーションに害を及ぼすかどうかを言う答えを探している場合は、セッションを制御している限り、そうではありませんセッションを終了せずにユーザーを離れることはありません。時間があれば、トークンを実装してください。
于 2013-02-26T20:45:52.840 に答える