背景:
これは実際には一般的なベストプラクティスの質問ですが、特定の状況に関するいくつかの背景が役立つ場合があります。
IPhone用の「接続された」アプリケーションを開発しています。 RESTサービスを介してバックエンドアプリケーションと通信します。アプリケーションを起動するたびにユーザーにユーザー名とパスワードを要求する必要がないように、「ログイン」サービスを公開します。初回起動時にユーザー名とパスワードを検証し、実際のデータに対する今後のWebサービスリクエストに使用できる認証トークンを返します。トークンには有効期限があり、その後ユーザー名/パスワードで再認証するように依頼します。
質問:
この種のトークンを生成して認証に使用するためのベストプラクティスは何ですか?
たとえば、...
これは、解決された問題であるに違いないと感じています。
この質問に対する他の回答からのフィードバック、追加の調査、オフラインの議論に基づいて、ここで私たちがやったことは...
ここでの相互作用モデルは、「記憶する」チェックボックスがオンになっているときにASP.NETのフォーム認証で使用されるモデルと本質的にまったく同じであることがすぐに指摘されました。 HTTPリクエストを行うWebブラウザではありません。 「チケット」は、フォーム認証が設定するCookieと同等です。フォーム認証では、基本的にデフォルトで「秘密鍵でデータを暗号化する」アプローチを使用します。
ログインWebサービスでは、このコードを使用してチケットを作成します。
string[] userData = new string[4];
// fill the userData array with the information we need for subsequent requests
userData[0] = ...; // data we need
userData[1] = ...; // other data, etc
// create a Forms Auth ticket with the username and the user data.
FormsAuthenticationTicket formsTicket = new FormsAuthenticationTicket(
1,
username,
DateTime.Now,
DateTime.Now.AddMinutes(DefaultTimeout),
true,
string.Join(UserDataDelimiter, userData)
);
// encrypt the ticket
string encryptedTicket = FormsAuthentication.Encrypt(formsTicket);
次に、要求のHTTPヘッダー内の有効なチケットをチェックするIParameterInspectorを追加するWCFサービスの操作動作属性があります。開発者は、認証を必要とする操作にこの操作動作属性を設定します。そのコードがチケットを解析する方法は次のとおりです。
// get the Forms Auth ticket object back from the encrypted Ticket
FormsAuthenticationTicket formsTicket = FormsAuthentication.Decrypt(encryptedTicket);
// split the user data back apart
string[] userData = formsTicket.UserData.Split(new string[] { UserDataDelimiter }, StringSplitOptions.None);
// verify that the username in the ticket matches the username that was sent with the request
if (formsTicket.Name == expectedUsername)
{
// ticket is valid
...
}
独自の認証システムを構築することは、常に「最悪の慣行」です。これは、認証システムを専門とする専門家に任せるのが一番いい種類です。
既存のアーキテクチャを再利用するのではなく、独自の「ログインサービスから期限切れのチケット」アーキテクチャを構築することに専念している場合は、Kerberosなどの類似システムの設計を推進した問題に少なくとも精通することをお勧めします。 。優しい紹介はこちらです:
http://web.mit.edu/kerberos/dialogue.html
また、過去20年間にKerberos(および同様のシステム)で見つかったセキュリティホールを調べて、それらを複製しないようにしてください。 Kerberosはセキュリティの専門家によって構築され、数十年にわたって慎重にレビューされましたが、次のような深刻なアルゴリズム上の欠陥が発見されています。
http://web.mit.edu/kerberos/www/advisories/MITKRB5-SA-2003-004-krb4.txt
自分の間違いよりも彼らの間違いから学ぶ方がはるかに良い。
Amazon.comは HMAC SHA-1メッセージトークン を使用してリクエストを認証および承認します。彼らはかなり大規模な商用サービスにこれを使用しているので、私は彼らのエンジニアリングの決定を信頼する責任があります。 Googleは OpenSocial API を公開していますが、これは多少似ています。 GoogleとAmazon.comがWebリクエストを保護するために同様の公開されたアプローチを使用していることに基づいて、これらはおそらく良い方法だと思います。
指定した2つの回答のいずれかで十分です。あなたのためにこれを行うフレームワークを見つけるかもしれませんが、実際には構築するのはそれほど難しくありません。 (私が働いていたすべての会社が独自にロールバックしました。)データベースに格納されたトークンと暗号化されたデータ「Cookie」の選択は、アーキテクチャ上の決定です。 Cookie復号化でCPUを噛みますか?ほとんどのアプリケーションでは、暗号化されたCookieを使用すると、大規模なパフォーマンスが向上します(懸念がある場合)。それ以外の場合は、単に好みの問題です。
WCFを使用しているため、CFNetworkを使用している場合はさまざまなオプションがあります。たとえば、NTLM認証またはダイジェスト認証です。
これはあなたの特定の質問に答えないことはわかっていますが、この問題(iPhone-Tomcat)にも直面しており、可能な限りWebサーバーで認証サービスを使用することにしました。ほとんどの場合、各リクエストに認証情報を含めることに大きなペナルティはありません。簡単なGoogleが、WCFおよびRESTfulサービスに関する多くのブログ投稿(およびStackOverflowに関するいくつかの関連する質問)を公開しています。
お役に立てれば!
以下を実装する必要があります。
まさにあなたが探しているOAuth2のワークフローです。車輪を再発明しないでください。
これは、有効期限が長いセッション識別子のように聞こえます。 Webアプリケーションでこれに使用されるのと同じ原則がここで適用できます。
セッション識別子は、情報をエンコードするのではなく、非常に大きなスペース(128ビット)からランダムに選択されます。サーバーは、セッション識別子とユーザーおよび有効期限などのその他の必要な情報を関連付けるレコードを保持します。クライアントは、リクエストごとに安全なチャネルでセッション識別子を提示します。
セキュリティは、セッション識別子の予測不能性に依存しています。非常に大きなスペースから、暗号化されたRNGでそれらを生成します。