web-dev-qa-db-ja.com

モバイルアプリケーション用のAPIの作成-認証と承認

概要

私はアプリケーション用に(REST)APIを作成したいと考えています。初期/主な目的は、モバイルアプリ(iPhone、Android、Symbianなど)が使用することです。私は、WebベースのAPIの認証と承認のさまざまなメカニズムを検討しています(他の実装を検討することによって)。基本的な概念のほとんどに頭を抱えていますが、まだいくつかの領域でガイダンスを探しています。私がやりたい最後のことは、車輪を再発明することですが、私の基準に合う標準的な解決策を見つけることはできません(ただし、私の基準は見当違いであるため、自由に批判してください)。さらに、APIを使用するすべてのプラットフォーム/アプリケーションでAPIを同じにする必要があります。

oAuth

oAuthに対する異議を投げ出します。なぜなら、それが最初に提供される可能性が高いとわかっているからです。モバイルアプリケーション(より具体的には非Webアプリケーション)の場合、認証のためにアプリケーションを(Webブラウザーに移動するために)残すのは間違っているようです。さらに、ブラウザがアプリケーション(特にクロスプラットフォーム)にコールバックを返す方法はありません(私は承知しています)。私はそれを行うアプリをいくつか知っていますが、それは間違っているように感じ、アプリケーションUXにブレークを与えます。

必要条件

  1. ユーザーがアプリケーションにユーザー名/パスワードを入力します。
  2. すべてのAPI呼び出しは、呼び出し元のアプリケーションによって識別されます。
  3. オーバーヘッドは最小限に抑えられ、認証の側面は開発者にとって直感的です。
  4. このメカニズムは、エンドユーザー(ログイン資格情報が公開されていない)と開発者(アプリケーション資格情報が公開されていない)の両方に対して安全です。
  5. 可能であれば、httpsを必要としません(決して厳しい要件ではありません)。

実装に関する私の現在の考え

外部開発者がAPIアカウントをリクエストします。彼らはapikeyとapisecretを受け取ります。すべてのリクエストには、少なくとも3つのパラメーターが必要です。

  • apikey-登録時に開発者に提供
  • タイムスタンプ-特定のapikeyの各メッセージの一意の識別子としても機能します
  • hash-タイムスタンプのハッシュ+ apisecret

Apikeyは、リクエストを発行するアプリケーションを識別するために必要です。タイムスタンプはoauth_nonceと同様に機能し、リプレイ攻撃を回避/軽減します。ハッシュは、指定されたapikeyの所有者からリクエストが実際に発行されたことを保証します。

認証されたリクエスト(ユーザーに代わって行われるリクエスト)の場合、access_tokenルートを使用するか、ユーザー名とパスワードのハッシュコンボを使用するかは未定です。いずれにしても、ある時点でユーザー名とパスワードのコンボが必要になります。その場合、いくつかの情報(apikey、apisecret、timestamp)のハッシュ+パスワードが使用されます。 この点についてのフィードバックをお待ちしています。 参考までに、ハッシュなしでシステムにパスワードを保存することはないため、最初にパスワードをハッシュする必要があります。

結論

参考までに、これは一般的にAPIを構築/構造化する方法のリクエストではなく、アプリケーション内のみから認証と承認を処理する方法のみです。

ランダム思考/ボーナス質問

リクエストの一部としてapikeyのみを必要とするAPIの場合、apikey所有者以外の誰かがapikeyを(平文で送信されるため)見ることができず、使用制限を超えてプッシュする過剰なリクエストを行うにはどうすればよいですか?たぶん私はこれを考えすぎているかもしれませんが、リクエストがapikey所有者に対して検証されたことを認証するものがあるべきではないでしょうか?私の場合、それはapisecretの目的であり、ハッシュされずに表示/送信されることはありません。

ハッシュといえば、md5対hmac-sha1はどうですか?すべての値が十分に長いデータ(つまり、apisecret)でハッシュされている場合、本当に問題になりますか?

以前は、ユーザー/行ごとのソルトをユーザーのパスワードハッシュに追加することを検討していました。私がそれをすることになった場合、アプリケーションはどのように使用されたソルトを知らなくても一致するハッシュを作成できますか?

185
jsuggs

私のプロジェクトでこれのログイン部分を行うことについて私が考えている方法は次のとおりです:

  1. ログインする前に、ユーザーはサーバーにlogin_tokenを要求します。これらは要求に応じて生成され、サーバーに保存され、おそらく制限された寿命を持ちます。

  2. ログインするために、アプリケーションはユーザーパスワードのハッシュを計算し、login_tokenでパスワードをハッシュして値を取得し、login_tokenと結合ハッシュの両方を返します。

  3. サーバーは、login_tokenが生成したものであることを確認し、有効なlogin_tokensのリストから削除します。サーバーは、保存されているユーザーのパスワードのハッシュとlogin_tokenを組み合わせ、送信された結合トークンと一致することを確認します。一致する場合、ユーザーを認証しました。

これの利点は、ユーザーのパスワードをサーバーに保存しないこと、パスワードが平文で渡されないこと、パスワードハッシュが平文で渡されるのはアカウントの作成時のみであることです(ただし、これに対処する方法があるかもしれません) login_tokenは使用時にDBから削除されるため、リプレイ攻撃から安全です。

43

それは1つにたくさんの質問です、私はかなりの数の人が最後までずっと読むことができなかったと思います:)

Webサービス認証の私の経験では、人々は通常それを過剰に設計し、問題はWebページで遭遇するものと同じです。可能な非常に単純なオプションには、ログインステップのhttpsが含まれ、トークンを返し、将来のリクエストに含める必要があります。また、HTTP基本認証を使用して、ヘッダーにデータを渡すこともできます。セキュリティを強化するには、トークンを頻繁にローテーション/期限切れにし、同じIPブロックからの要求を確認し(モバイルユーザーがセル間を移動するときに面倒になる可能性があります)、APIキーなどと組み合わせます。または、ユーザーを認証する前にoauthの「キーを要求する」ステップを実行し(以前の回答で既にこれを提案しているので良い考えです)、それをアクセストークンを生成するための必須キーとして使用します。

私はまだ使用していませんが、oAuthのデバイスフレンドリーな代替手段として多くのことを聞いていますが、 xAuth です。それを見て、あなたがそれを使用するなら、私はあなたの印象が何であるかを聞くことに本当に興味があるでしょう。

ハッシュについては、sha1の方が少し優れていますが、ハングアップしないでください。デバイスが簡単に(そしてパフォーマンスの意味で迅速に)実装できるものなら何でも問題ありません。

それがお役に立てば幸いです:)

13
Lorna Mitchell

TwitterはoAuthの外部アプリケーションの問題に対処しました xAuth と呼ばれるバリアントをサポートします。残念ながら、この名前を持つ他のスキームがすでにたくさんあるので、整理するのが混乱する可能性があります。

プロトコルoAuthです。ただし、リクエストトークンフェーズをスキップし、ユーザー名とパスワードを受信するとすぐにアクセストークンペアを発行します。 ( ここのステップE から始まります。)このinitial要求と応答セキュリティで保護する必要があります-ユーザー名とパスワードを送信しています平文およびアクセストークンとシークレットトークンの受信。アクセストークンペアが設定されると、最初のトークン交換がoAuthモデルを介して行われたかxAuthモデルを介して行われたかは、残りのセッションではクライアントとサーバーの両方に関係ありません。これには、既存のoAuthインフラストラクチャを活用でき、モバイル/ Web /デスクトップアプリケーションに対してほぼ同じ実装を使用できるという利点があります。主な欠点は、アプリケーションにクライアントのユーザー名とパスワードへのアクセスが許可されることですが、要件がこのアプローチを義務付けているように見えます。

いずれにせよ、あなたの直観とここにいる他のいくつかの回答者の直観に同意したいと思います:ゼロから新しい何かを構築しようとしないでください。セキュリティプロトコルは簡単に開始できますが、常にうまくやることは難しく、複雑になるほど、サードパーティの開発者がそれらに対して実装できる可能性は低くなります。仮想プロトコルはo(x)Auth-api_key/api_secret、nonce、sha1 hashingと非常に似ていますが、開発者が独自のロールを作成する必要がある多くの既存のライブラリの1つを使用できる代わりに。

9
lantius

では、モバイルアプリケーションの認証と承認の側面を処理するサーバーサイド認証メカニズムのようなものを求めています。

これが事実であると仮定すると、私は次のようにアプローチします(ただし、私はJava開発者なので、C#の人はそれを別の方法で行います):

RESTful認証および認可サービス

  1. これはHTTPSでのみ機能し、盗聴を防ぎます。
  2. RESTEasySpring Security 、および CAS (複数のアプリケーションにわたるシングルサインオンの場合)の組み合わせに基づきます。
  3. ブラウザとWeb対応クライアントアプリケーションの両方で動作します
  4. ユーザーが詳細を編集できるようにするWebベースのアカウント管理インターフェイスと、承認レベルを変更する管理者(特定のアプリケーション用)があります

クライアント側セキュリティライブラリ/アプリケーション

  1. サポートされているプラ​​ットフォーム(Symbian、Android、iOSなど)ごとに、プラットフォームのネイティブ言語(Java、ObjectiveC、Cなど)でセキュリティライブラリの適切な実装を作成します。
  2. ライブラリは、指定されたプラットフォームで利用可能なAPIを使用してHTTPSリクエストの形成を管理する必要があります(例:JavaはURLConnectionなどを使用します)
  3. 一般的な認証および承認ライブラリ(「cos」だけです)のコンシューマーは特定のインターフェイスにコードを記述し、変更されても満足しないので、非常に柔軟であることを確認してください。 Spring Securityなどの既存の設計選択に従ってください。

さて、30,000フィートからの眺めが完成したので、どうやってそれをやりますか?ブラウザクライアントを使用して、サーバー側にリストされているテクノロジに基づいて認証および承認システムを作成するのはそれほど難しくありません。 HTTPSと組み合わせて、フレームワークは、認証プロセスによって生成され、ユーザーが何かをしたいときに使用される共有トークン(通常はCookieとして提示される)に基づいて、安全なプロセスを提供します。このトークンは、リクエストが発生するたびにクライアントからサーバーに提示されます。

ローカルモバイルアプリケーションの場合、次のことを行うソリューションを求めているようです。

  1. クライアントアプリケーションには、メソッド呼び出しへのランタイムアクセスを制御する定義済みのアクセス制御リスト(ACL)があります。たとえば、特定のユーザーはメソッドからコレクションを読み取ることができますが、ACLは名前にQが含まれるオブジェクトへのアクセスのみを許可するため、コレクション内の一部のデータはセキュリティインターセプターによって静かにプルされます。 Javaでは、これは簡単です。呼び出しコードでSpring Securityアノテーションを使用し、適切なACL応答プロセスを実装するだけです。他の言語では、あなたは独力で、おそらくセキュリティライブラリを呼び出す定型的なセキュリティコードを提供する必要があります。言語がAOP(アスペクト指向プログラミング)をサポートしている場合、この状況で最大限にそれを使用します。
  2. セキュリティライブラリは、接続を維持する必要がないように、現在のアプリケーションのプライベートメモリに承認の完全なリストをキャッシュします。ログインセッションの長さによっては、これは一度も繰り返されない操作になる場合があります。

何をするにしても、独自のセキュリティプロトコルを発明しようとしないでください。現在利用可能で無料のアルゴリズムよりも優れたアルゴリズムを作成することはできません。また、人々はよく知られたアルゴリズムを信頼しています。したがって、セキュリティライブラリが、SSL、HTTPS、SpringSecurity、およびAES暗号化トークンの組み合わせを使用してローカルモバイルアプリケーションの承認と認証を提供すると言うと、市場ですぐに信用を得ることができます。

これがお役に立てば幸いです。さらに情報が必要な場合は、お知らせください。SpringSecurity、ACLなどに基づいたWebアプリケーションを多数作成しました。

8
Gary Rowe

パーティーに遅刻しましたが、この問題に興味のある人のために考慮すべき点をいくつか追加したかったのです。私はモバイルAPIセキュリティソリューション( approov )を行っている会社で働いているので、この分野全体が私の興味に間違いなく関連しています。

まず、モバイルAPIを保護する際に考慮すべき最も重要なことは、どれだけの価値があるかです。銀行にとっての正しい解決策は、ただ楽しみのために物事をしている人にとっての正しい解決策とは異なります。

提案されたソリューションでは、少なくとも3つのパラメーターが必要であることに言及しています。

  • apikey-登録時に開発者に与えられます
  • タイムスタンプ-特定のapikeyの各メッセージの一意の識別子としても機能します
  • hash-タイムスタンプのハッシュ+ apisecret

これが意味するのは、一部のAPI呼び出しではユーザー名/パスワードが不要なことです。これは、ログインを強制したくないアプリケーション(たとえば、オンラインショップでの閲覧)に役立ちます。

これは、ユーザー認証の問題とはわずかに異なる問題であり、ソフトウェアの認証または認証に似ています。ユーザーはいませんが、APIへの悪意のあるアクセスがないことを確認する必要があります。そのため、APIシークレットを使用してトラフィックに署名し、APIにアクセスするコードが本物であることを識別します。このソリューションの潜在的な問題は、アプリのすべてのバージョン内の秘密を明かさなければならないことです。誰かが秘密を抽出できる場合、彼らはあなたのAPIを使用し、あなたのソフトウェアになりすますが、好きなことをします。

その脅威に対抗するために、データの価値に応じてできることがたくさんあります。 難読化は、秘密の抽出を難しくする簡単な方法です。それを行うツールはありますが、Androidの場合はそうですが、ハッシュを生成するコードが必要であり、十分に熟練した個人は常にハッシュを直接行う関数を呼び出すことができます。

ログインを必要としないAPIの過度の使用を緩和する別の方法は、トラフィックをthrottleして、疑わしいIPアドレスを潜在的に識別してブロックすることです。どの程度の労力を費やすかは、データの価値に大きく依存します。

それを超えて、簡単に私の仕事の領域に入ることができます。とにかく、APIを保護するもう1つの側面であり、重要であり、フラグを立てたいと思ったものです。

5
ThePragmatist