既存のREST SSL経由でアクセスされるAPIのセキュリティを向上させたいと考えています。Webサービスはマルチテナントであり、各テナントにはTenantIdが割り当てられています。
私が直面している問題は、次のように要約できます。
現在
現在、私たちは手動で(つまり、アウトプロセス-電話などで)各クライアントにAPIキーを発行しています。これは、各リクエストのHTTPヘッダーとして含まれています。このAPIキーはTenantIdにマッピングされます。クライアントがREST APIにログインリクエストを送信すると、TenantIdが決定されます。これにより、正しいテナントデータベースのユーザー名/パスワードを確認できます。これが成功すると、時間制限付きのHTTP Cookie。このCookieは、後続のREST要求で使用されます。内部的に、そのCookieはセッションにリンクされており、セッションにはデータベースの負荷を減らすためのユーザープロファイル情報が含まれています。
これには、固有のセキュリティリスクがあることを認識しています。 APIキーは、逆アセンブルされたクライアントソースコードから簡単に抽出できます。また、誰でも読み取り可能なJavaScriptのSPAとして独自のクライアントを構築する予定です。キーを取り消したり変更したりできますが、より安全な標準化された実装を探しています。
代替
私が理解しているように、Cookieの代わりにトークンベースを使用できます。 HMACはWebアプリケーションの一般的な認証メカニズムですが、これにはクライアントとサーバーに共有シークレットを格納する必要があります。この秘密には、上記のAPIキーと同じ問題があるようです。漏れる可能性があります。
また、JWTについても少し読みました 。これは、サーバーがユーザーの「セッション」データをトークンに保持できるため、データベース呼び出しの数を減らし、HMACの概念を拡張しているようです 。ユーザー/プロファイル情報。 JWTトークンは、ユーザー名/パスワードのログインが成功した結果として使用されます。したがって、ここで共有秘密の問題はありませんか?
また、OAuth2、特に Resource Owner Password Credentials Grant についても少し読んだ。 OAuth2が私の問題を解決するかどうかはわかりませんが。
テナントの決定
最初のステップは、テナントの決定です。 APIキーを使用してTenantIdにマップする代わりに、次のいずれかを行うことができます。
アプリケーション呼び出し元の検証
次に、特定のクライアントアプリケーションがREST APIにアクセスすることを許可されているかどうかを判断する必要があります。この点で、私は優れたアイデアを完全に失っています。OAuth2が救援?
これを解決する唯一の方法は、ユーザーがログインした後、一時的に有効期限が切れるAPIキーを呼び出し側のアプリケーションに発行することです。これは、アプリケーションが不正でないことを保証するものではありませんが、攻撃者へのリスクを軽減しますユーザーの資格情報へのアクセスも取得したユーザー。
現在のHTTP Cookieソリューションは受け入れられますか?代わりにトークンベースの認証メカニズムに移行する必要がありますか?
どんなアドバイスでも歓迎します。私は大量の情報を調べて、これらすべてに頭を悩ませようとしています。どんなご指導も喜んで承ります!
oauth 2.0(RFC 6749))を確認する必要があります。これには、要件を満たすことができる多くのフローがあります。
まず、クライアントが公開されているか機密であるかを知る必要があります。シークレットを維持できないため、クライアントがWebブラウザーまたはモバイルデバイスにダウンロードされたアプリである場合、クライアントAPIキーを発行している間は無意味です。サーバーの場合は、APIキーが適しています。それが最初の検討事項です。 rfcのセクション2.1はクライアントのタイプを扱っており、これにより適用可能なフローが決まります。
クライアントサービスのIDを、クライアントが機能するユーザーから分離する必要があります。単一のテナンシーのみにスコープを設定したい場合は、バックエンドデータベースにユーザーとテナントを関連付け、APIキーをユーザーまたはユーザー+テナントと関連付ける必要があります。ユーザーが複数のテナントに参加できるサービスを実装したので、ケースに適用される場合とされない場合があります。ユーザーがWebブラウザーから自分のユーザー名とパスワードを提供できるように、リソース所有者のパスワード資格情報付与要求を正常に使用しました。帯域外メソッドを使用してクライアントを認証したため、ユーザーの資格情報は必要ないようです。ただし、クライアントがWebブラウザーまたはモバイルアプリの場合、クライアント認証に依存することはできず、ユーザーから承認を得る必要があります。つまり、ユーザーの資格情報を提供する必要があります。
使用するフローに関係なく、次のような応答が返されます。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
返されたアクセストークンは、クライアントがリクエストで使用するもので、リクエストが承認されていることをサーバーに証明できます。
Authorizationヘッダーには、「bearer」または「mac」の2つのオプションがあります。
Authorization: Bearer xxxxxx
クライアントがTLSを使用している場合、ベアラートークンを使用するのが簡単です。詳細については、RFCのセクション7.1を参照してください。
最後に、アクセストークンは一時的なものにすぎないため、アクセストークンが有効期限に近づくか、またはそれを超えると、クライアントは更新トークンを使用して新しいアクセストークンを要求できます。更新トークンを使用するかどうかは、あなた次第です。クライアントは、少なくともAPIキーに使用するのと同じレベルの保護を安全に保存する必要があります。ご使用のシステムでは、アクセス存続期間が十分でユーザー認証が不要な場合、サーバー間相互作用にリフレッシュトークンは不要です。ユーザー認証が必要な場合、クライアントストレージが十分なレベルの保護を提供していれば、更新トークンが役立つことがあります。
テナントをどのように識別するかについては、現時点では問題ないと思います。各クライアントにはsome種類の識別子が必要です。APIキーは他のAPIと同じくらい優れています。すべてがSSLで実行されていることを考えると、(少なくとも転送中に)公開されることを心配する必要はありません。
あなたはclient-side APIキーのストレージについて心配しているようですが、最終的にはあなたの仕事ではありません。個人情報を安全に保つのはクライアントの責任です(PIN=)を守るのは銀行の仕事ではありません。あなたの仕事はサーバーとクライアントを誤用から保護することです。1これを行う方法は、APIキーやセッションを取り消す/ブロックする機能を持っていることです。
CookieとHMACの引数は、あなたが考えるほど重要ではないかもしれません。クッキーからトークンに切り替えた場合、何が変わるかを自問してみてください。署名されていれば、HMACは確かにより安全ですが、Cookieの内容を簡単に暗号化できます。最終的には、Cookieと同じストレージの問題が発生します。焦点を当てるべき重要な部分は、誰かがそれにアクセスすることができた場合、誰かがどのくらいの損害を与えることができるかです。これにより、A。Cookie /トークンをどの程度安全にする必要があるか、およびB.サーバー/クライアントが悪意のある手に渡った場合にどのように保護できるかについて考えるようになります。
クライアントauthorizationも処理する必要がある場合は、OAuthを設計することを前提として、OAuthを確認する必要があります。
別の方法は、公開鍵と秘密鍵を使用することです。
クライアントアプリ(angularjsなど)はサーバーの公開キー(web apiなど)を持ちます。
サーバーの公開鍵を使用して、クライアントはユーザーの資格情報(ユーザー名、ハッシュされたパスワードなど)を暗号化する必要があります。生成されたトークンはサーバーに送信されます。ヘッダーまたはクエリスティングのいずれかによる
サーバーはトークンを復号化し、ユーザー名とハッシュ化されたパスワードを取得します。次に、永続的なユーザー名+ハッシュされたパスワードをデータベースから取得します。認証は、両方のハッシュされたパスワードが一致するかどうかを確認することです(1つはトークンから、もう1つはデータベースから)。
この代替方法では、ユーザーのパスワードはプレーンテキストとして送信されません。送信前に暗号化/ハッシュ化されます。クライアントは、そのトークンをlocalstorage(browser)に保存するか、サーバーを呼び出すたびに新しいトークンを生成できます。