20

JavaScript ベースのアプリで動作するように、PHP で REST API を構築しています。すべてのリクエストは JSON として処理され、一部のリクエストには認証が必要です。

リクエストの例は次のとおりです。

$.ajax({
    type: 'GET',
    url: 'http://domain.com/api/posts/recent.json',
    headers: {
        Authorization: 'X-TRUEREST ' + $.param({
            username: 'johndoe',
            password: '********'
        })
    },
    success: function(response){
            // Handle response here (includes auth errors too)
    },
    error: function(a,b,c) {

    }   
});

このプラグインのコードに基づいて HTTP 認証ヘッダーを使用しました: https://github.com/kvz/cakephp-rest-plugin/blob/master/Controller/Component/RestComponent.php#L532

ご覧のとおり、ヘッダーで渡されたパラメーターを取得し、ユーザーがまだシステムにログインしていない場合は、それらを使用してシステムにログインします。私が言えることから、彼らは認証資格情報がデータの要求とと​​もに渡されることを期待しています。

この例は次のとおりです (私のサンプルアプリでは CakePHP を使用していないことに注意してください):

if ( $loggedIn ) { // logged in is true of false based on session existing

    // Then return the JSON as normal

} else {

    // Grab HEADERS INFO

    $headers = $_SERVER['HTTP_AUTHORIZATION'];
    $parts = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);

    // Then use the parts to find a user in the DB... and populate $user

    if($user){

        $this->Auth->login($user); // login the user with our authentication code

        // Then return JSON as normal

    } else {
        print json_encode(array('auth'=>false))
    }

}

私が持っているいくつかの質問:

質問 1:なぜ HTTP 認証とヘッダーを使用するのですか? 私が知る限り、私がそれらを間違って使用していない限り、彼らは私に何も提供してくれませんか? JS のデータ パラメーターでユーザー名とパスワードを渡さないのはなぜですか?

質問 2:前述のように、API 設計は上記の Cake プラグインに基づいていますが、私が見る限り、彼らは常にすべてのリクエストでユーザー名とパスワードを渡し、ユーザーがログインしている場合にそれを使用するかどうかを決定します。これは正しいですか?私には、認証とデータの要求を別々に処理する必要がある可能性が高いようです。そうしないと、リクエストごとに送信できるように、JavaScript のどこかにユーザー名とパスワードを保存する必要があります。

それが次の質問につながります...

質問 3:ユーザーがログインしているかどうかを確認するにはどうすればよいですか? 変数を true に設定し、それをすべてのリクエストで JSON の一部として渡すことはできますが、セッションは外部デバイスと連携できますか?

4

4 に答える 4

22

REST API を設計している場合は、REST の原則に従う必要があります。認証のために強調すべき重要な点が 2 つあります。

  1. URI によるリソースの識別
  2. サーバー提供のリンクを介して状態が遷移します。

原則 1 に従うには、認証を URIから除外する必要があります。 http://example.org/list-of-stuff?auth-token=12345はと異なるリソースhttp://example.org/list-of-stuff?auth-token=67890ではないため、異なる URI を持つべきではありません。URI が異なると、異なるユーザー間でリソースをキャッシュすることもできなくなります。

一般に、条件によってリソースが異なる場合、その条件は URI に含まれている必要があります。たとえば、多くの Web サイトには/profileURL がありますが、どのプロファイルが表示されるかは、目に見えない「誰がログインしているか」の状態によって異なります。これはRESTful ではありません。代わりに、URL にはユーザーを含める必要があります (例: /profiles/username. そのリソースを実際に表示できるかどうかは、そのリソースを表示する権限があるかどうかによって異なります。これは、権限のあるユーザーとして認証されているかどうかによって異なります。認証は、リソース識別とは別のレイヤーです。(たとえば、他の人のプロフィールを見ることができる管理者ユーザーがいるとします。/profileURL、彼が他のプロフィールを見る方法をどのように設計しますか? リソースの存在は明らかに、それを見る能力や誰がそれを見ているかということとは別のものです。)

そのため、URI のパラメーターを介して認証を行うべきではないことを確立しました。HTTP を使用しているため、ヘッダーで提供するか、HTTP 自体の外部で提供することができます。

あまり一般的ではありませんが、一部の REST API は、クライアント証明書を使用して SSL レイヤーで認証を処理します。これは技術的な観点からは素晴らしいことですが、ユーザー エクスペリエンスは不可解でひどいものです。この記事は2008年のものですが、何も改善されていません。このアプローチは、ブラウザー JS から簡単にスクリプト化することもできません。また、ブラウザーの外部であっても、クライアント証明書を提供する必要があるアプリケーションを作成するのは面倒です。サーバー側での開発も困難です。ほとんどの Web スクリプト環境では、クライアント証明書のような難解な SSL 機能はもちろんのこと、SSL 層のものに簡単にアクセスできないためです。アプリケーションは、要求で提供された証明書 ID を認識できない場合があります。

したがって、ヘッダーに HTTP が残ります。特別な URL で「ログイン」してトークンを取得する従来の Cookie ベースの認証を使用するか、HTTP でネイティブにサポートされている HTTP 認証を使用できます。

HTTP 認証はステートレスであるため、RESTful 原則に関してははるかに優れています。(これにより、3 番目の質問は無意味になります。「ログイン」または「ログアウト」状態はありません。要求に対して正しい資格情報を提供したか、提供しなかったかのどちらかです!) 最初にアクセスしたことを確認する必要はありません。特別な URL を取得し、保存する必要があるマジック トークン (突然期限切れになる可能性があります) を取得したら、毎回資格情報を使用してリクエストを発行するだけです。リソースへのアクセスが承認されていない場合は、特定の HTTP 応答コード (401) とヘッダー (WWW-Authenticate、Authorization)、および一連の明確に定義された動作があります。また、さまざまな認証方法で拡張可能です。少なくとも XmlHTTPRequest に固執している場合は、かなりの量の JavaScript もサポートされています。(まあ、jQuery 1.7.

欠点は、一般的に使用され、十分にサポートされている HTTP 認証方法は Basic と Digest だけであり、どちらもあまり安全ではないことです。https のみを使用する場合はおそらく問題ありませんが、それ以外の場合はひどいものです。

また、HTTP 認証は、人間による通常のブラウザーの使用には役に立ちません。カスタム ログイン ページがなく、「パスワードを忘れた」機能やその他の認証のカスタマイズを提示する方法がありません。また、ブラウザー メーカーは、「ログアウト」する簡単な方法を提供していません (つまり、パスワードを忘れる)。現在のレルムの資格情報)!

Cookie ベースの認証はほとんどの制御を提供しますが、サーバー側とクライアント側の認証状態を維持する必要があり、セッション固定セッションの構成要素など、他の多くのセキュリティ問題について心配する必要があります。! IP アドレス、ユーザー エージェント、何らかの組み合わせですか? 認証されたセッションは、有効期限が切れるまでどのくらいの期間有効でなければなりませんか? プロキシが関係していて、IP アドレスが頻繁に変更される場合はどうなりますか? マジック トークンの有効期限が切れたら、どうすればよいですか? ユーザーが許可されていない場合はどうすればよいですか? (HTTP 401 応答は使用できません。サイト固有の独自のメソッドを定義する必要があります。) 本質的には、独自の複雑なセッションと認証プロトコルを定義するか、他の誰かのものを採用する必要があります。少なくとも HTTP 認証では、攻撃者が Authenticate ヘッダーを読み取ることだけを心配する必要があり、SSL を使用することでその問題は解決します。

于 2013-02-03T20:47:53.550 に答える
8

質問 1: なぜ HTTP 認証とヘッダーを使用するのですか? 私が知る限り、私がそれらを間違って使用していない限り、彼らは私に何も提供してくれませんか? JS のデータ パラメーターでユーザー名とパスワードを渡さないのはなぜですか?

ここでの HTTP 認証は、開発者の個人的な選択のようです。OpenIDを使用できます。トークンを使用できます。HTTP ヘッダー認証を使用できます。セッション/クッキーを使用できます。必要に応じて、 RSA キー認証またはSSL クライアント証明書を使用することもできます。


質問 2: 前述のように、API 設計は上記の Cake プラグインに基づいていますが、私が見る限り、彼らは常にすべてのリクエストでユーザー名とパスワードを渡し、ユーザーがログインしている場合にそれを使用するかどうかを決定します。これは正しいですか?私には、認証とデータの要求を別々に処理する必要がある可能性が高いようです。そうしないと、リクエストごとに送信できるように、JavaScript のどこかにユーザー名とパスワードを保存する必要があります。

ユーザー名とパスワードをプレーンテキストで公開することは絶対に避けてください (技術的にはそのまま保存するべきではありませんが、それは問題ではありません) API で公開トークンを使用するか、一意の Cookie ID を使用します。個人的には、ユーザーが何かにログインしているかどうかを確認するために使用します。必要に応じて、AJAX に送信させ、ID を内部でトークンにマップします。$_SESSION["id"]


質問 3: ユーザーがログインしているかどうかを確認するにはどうすればよいですか? 変数を true に設定し、それをすべてのリクエストで JSON の一部として渡すことはできますが、セッションは外部デバイスと連携できますか?

この回答にリンクされているために使用する機能があります。理想的には、セッションを使用して有効なログインを確認し、インデックス ( など$_SESSION["id"]) の値をそのアカウントに固有の値 (通常、これはデータベース ID) に設定する必要があります。

編集: OPのコメントを読んだ後、リクエストを行う前に、セッションCookieがログインしているデバイスにあることを確認する必要があります

これはセキュリティの脆弱性であるため、フィールドをログインと見なさないでください。value: true

于 2013-02-03T19:06:19.117 に答える
4

URI を使用して REST API に情報を渡すことと、http 簡易認証を使用して特定のサーバーへのアクセスを承認することを (おそらく意図的に) 混合していると思います。

HTTP 認証を使用してユーザーを処理することもできますが、それはあまり良い選択ではありません (他の回答で説明されているように)。ユーザー、セッション、セキュリティ トークンなどはアプリ ロジックで処理する必要がありますが、API アクセスはサーバーで安全に保護することもできます (http シンプルまたはダイジェスト セキュリティ、NTLM、IP フィルタリングなどを使用)。Webサーバーにセキュリティの負担/分離の問題/ある種のテストサイト/などを任せます。

シナリオの例では、テスト ゾーン サーバーで保護されたサーバー アクセスへの http セキュリティを処理していますが、アプリの REST API は、サーバーのセキュリティ チェックに合格したすべてのユーザーに対して、さまざまなユーザー、トークン、アクセス許可レベルなどを受け入れて処理します。

詳細については、この質問を探してください

于 2013-02-03T22:51:36.673 に答える
1

質問 1: なぜ HTTP 認証とヘッダーを使用するのですか? 私が知る限り、私がそれらを間違って使用していない限り、彼らは私に何も提供してくれませんか? JS のデータ パラメーターでユーザー名とパスワードを渡さないのはなぜですか?

クエリ文字列は URI の一部です。URI は REST によるリソース識別子であるため、リソース状態の一部です。ユーザーの ID、資格情報などは、クライアント状態の一部です。クライアント状態を URI に追加してクライアント状態とリソース状態を混在させると、REST のステートレス制約に違反します。POST、PUT、DELETE などの他のリクエストのデータ部分は、リソース表現を記述するためのものであるため、認証データを一緒に送信しないでください。ヘッダーを送信するのが最善の方法です。HTTP には専用の Authorization ヘッダーがあるため、それを使用する必要があります。

質問 2: 前述のように、API 設計は上記の Cake プラグインに基づいていますが、私が見る限り、彼らは常にすべてのリクエストでユーザー名とパスワードを渡し、ユーザーがログインしている場合にそれを使用するかどうかを決定します。これは正しいですか?私には、認証とデータの要求を別々に処理する必要がある可能性が高いようです。そうしないと、リクエストごとに送信できるように、JavaScript のどこかにユーザー名とパスワードを保存する必要があります。

ステートレスを維持するために、サーバーはすべてのリクエストを認証する必要があります。このライブラリのロジックについてはよくわかりません。何が起こるかを説明するのにログインという用語は間違っていると思いますが、REST の観点からは、HTTP 標準を適切に使用し、通信がステートレスである限り、実装の詳細は重要ではありません。あなたが質問してからコードが変更されました。

質問 3: ユーザーがログインしているかどうかを確認するにはどうすればよいですか? 変数を true に設定し、それをすべてのリクエストで JSON の一部として渡すことはできますが、セッションは外部デバイスと連携できますか?

クライアント状態であるため、サーバーはクライアントがログインしているかどうかを気にしません。アクセス許可が必要なリクエストを送信する場合は、ユーザーの認証に必要なデータを送信する必要があります。

于 2015-10-06T15:28:13.797 に答える