web-dev-qa-db-ja.com

REST信頼できるモバイルアプリケーションのみのAPIを保護する方法

REST APIが信頼できるクライアントによって生成されたリクエストにのみ応答することを確認するにはどうすればよいですか?私の場合、自分のモバイルアプリケーションですか?他のソースからの不要なリクエストを防ぎたいです。ユーザーはシリアルキーなどを入力する必要があります。これは、インストール時にユーザーの操作を必要とせずに、裏で行われる必要があります。

私の知る限り、HTTPSは、通信しているサーバーが本人であることを検証するためだけのものです。もちろん、HTTPSを使用してデータを暗号化します。

これを達成する方法はありますか?

pdate:ユーザーは、ユーザーのログインを必要としない読み取り専用アクションを実行できますが、ユーザーのログインを必要とする書き込みアクションも実行できます(アクセスによる認証トークン)。どちらの場合も、信頼できるモバイルアプリケーションからのリクエストのみにAPIが応答するようにします。

APIは、モバイルアプリケーションを介して新しいアカウントを登録するためにも使用されます。

pdate 2:これには複数の答えがあるようですが、正直に答えとしてフラグを立てるのはわかりません。それができると言う人もいれば、できないと言う人もいます。

100
Supercell

できません。

個人、ハードウェアクライアント、ソフトウェアクライアントなど、エンティティエンティティを確認することはできません。あなたはそれらがtellingが正しいことを確認し、次に仮定が正直であることを確認することができます

たとえば、GoogleはそれがGmailアカウントにログインしていることをどのようにして知っていますか?彼らは単に私にユーザー名とパスワードを尋ね、それを確認し、次に正直と仮定します誰がその情報を持っているのでしょうか?ある時点で、Googleはこれでは不十分であると判断し、動作検証(奇妙な動作を探す)を追加しましたが、それでもpersonを実行することに依存しています動作、次に動作を検証します。

これは、クライアントの検証とまったく同じです。クライアントの動作のみを検証でき、クライアント自体は検証できません。

したがって、SSLを使用すると、クライアントに有効な証明書があるかどうかを確認できます。つまり、アプリをインストールして証明書を取得し、すべての新しいコードを実行できます。

だから問題は、なぜこれがそれほど重要なのかということです。これが本当の懸念であるなら、私はあなたの太ったクライアントの選択に疑問を投げかけるでしょう。おそらく、Webアプリを使用する必要があります(そのため、APIを公開する必要はありません)。

以下も参照してください。 Androidアプリケーション のSSL証明書検証の無効化] ==

and: モバイルアプリのクライアントSSL証明書はどのくらい安全ですか?

49
Morons

ユーザーのログインやSSLを介した通信に慣れていると思いますので、質問のより興味深い部分、つまり読み取り専用のアクションを確実にする方法に焦点を当てます- notserを認証する必要があります-自分のクライアントアプリからのみ受け入れられますか?

何よりも前に、fNekが以前の回答でほのめかしたマイナス面があります-クライアントアプリは潜在的に敵意のあるユーザーの手に渡っています。それらを検査し、通信を検査し、コードを分解できます。 保証誰かがクライアントをリバースエンジニアリングしてREST APIを悪用することはありません。しかし、それは何気ない試みの前。

とにかく、一般的なアプローチは次のとおりです。

  • クライアントには秘密が含まれています
  • リクエストを行う場合、リクエストパラメータをシークレットと連結し、結果をハッシュします
  • このハッシュはリクエストとともに送信され、サーバーによってチェックされます

たとえば、/products/widgetsに対するGETリクエストを想像してみてください

クライアントシークレットが「OH_HAI_I_IZ_SECRET」であるとしましょう

HTTP動詞、URL、シークレットを連結します。

GET/products/widgetsOH_HAI_I_IZ_SECRET

そして、その SHA-1 ハッシュを取ります:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

それを一緒に送信すると、リクエストは次のようになります。

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

最後に、誰かが少なくとも個々のリクエストをリプレイできないようにするには、タイムスタンプも取得し、それをパラメーターとハッシュに追加します。例えば現在、Unix時間では1384987891です。それを連結に追加します。

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891

ハッシュそれ:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

そして送ってください:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1

サーバーはハッシュをチェックし、タイムスタンプが最新であることも確認します(たとえば、時計が完全に同期していないことを考慮して5分以内)

警告!モバイルアプリについて話しているため、誰かの携帯電話の時計が間違っているという明確なリスクがあります。またはタイムゾーンが間違っています。か何か。ハッシュに時間を追加すると、一部の正当なユーザーが壊れる可能性があるため、そのアイデアは慎重に使用してください。

32
Carson63000

Android=に興味がある人なら、あなたが受け取ったリクエストがあなたのアプリから送信されたことを確認できます。

簡単に言うと、アプリをグーグルにアップロードするときは、自分(およびグーグル)だけが知っている一意のキーを使用して署名します。

確認プロセスは次のように行われます。

  1. あなたのアプリはグーグルに行き、認証トークンを求めます
  2. アプリはトークンをバックエンドに安全に送信します
    1. バックエンドはgoogleにアクセスし、アプリから取得した認証トークンを確認します。
    2. 次に、バックエンドは、アプリが署名した一意のキーが一致するかどうかをチェックします。一致しない場合は、それがアプリではなかったことを意味します...

それとそれを実装する方法を説明する完全なブログはここにあります: http://Android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-Android.html

17
ndori

@Moronsが彼の回答で述べたように、接続の反対側にあるエンティティを検証することは非常に困難です。

ある程度の信頼性を提供する最も簡単な方法は、サーバーに、実際のエンティティだけが知っているであろうある秘密をチェックさせることです。ユーザーの場合、それはユーザー名とパスワードである可能性があります。ユーザーがいないソフトウェアの場合、秘密を埋め込むことができます。

これらのアプローチの問題は、クライアントをある程度信頼する必要があることです。誰かがアプリをリバースエンジニアリングしたり、パスワードを盗んだりすると、彼らはあなたになりすますことができます。

実行可能ファイルで難読化することにより、秘密情報の抽出を困難にするための手順を実行できます。 Javaの難読化ツールであるProGuardのようなツールはこれに役立ちます。他の言語での難読化についてはあまり知りませんが、同様のツールがあると思われます。TLS接続を使用すると、人々を防ぐのに役立ちますトラフィックをスヌーピングしますが、MITM攻撃を防ぎません Pinning はその問題の解決に役立ちます。

私はCriticalBlue(完全開示!)という会社で働いています。この会社は、この信頼の問題に対処しようとする Approov という製品を持っています。現在はAndroid/iOSで動作し、サーバーがクライアントアプリの整合性をチェックするメカニズムを提供します。これは、クライアントにランダムチャレンジへの応答を計算させることによって行われます。クライアントは、インストールされたアプリパッケージの属性を使用して応答を計算する必要があります。これは、偽造が難しく、高度な改ざん防止メカニズムが含まれています。

それはあなたがあなたのAPIへの真正性の証明としてそれからあなたが送ることができるトークンを返します。

このアプローチとの重要な違いは、クライアントで認証チェックを無効にすることは可能ですが、認証トークンを取得しないと、サーバーでアプリを検証する必要があるということです。また、ライブラリは、その中にある実行可能ファイルの特性と密接に結び付いているため、偽のアプリに埋め込んで動作させるのは非常に困難です。

誰かがAPIをハッキングしようとする可能性と、それがどれほどのコストになるかを判断するために、API開発者が行う必要があるコスト/メリット分析があります。アプリケーションの単純なシークレットチェックは簡単な攻撃を防ぎますが、より断固とした攻撃者から身を守ることは、おそらくかなり複雑で、潜在的にコストがかかります。

5
ThePragmatist

それで、ほとんどのアプリケーションにとってこれは非常に過剰であることを、始める前に言及する価値があります。ほとんどのユースケースでは、単一の有効な証明書やトークンを持っているだけで十分です。アプリの逆コンパイルなどの困難な作業を伴う場合、非常に貴重なデータを提供しない限り、ほとんどのハッカーでさえ邪魔になりません。しかし、ねえ、その答えの楽しいところはどこですか?

つまり、プログラムに署名するために使用される デジタル署名 sのような非対称暗号をセットアップすることができます。各アプリは、単一のCAによって発行され、ユーザーの接続時に検証される個別の証明書を持つことができます。 (最初の登録時または最初のインストール時)その証明書が認証されると、特定の1つのデバイス識別子( Android ID など)に対して有効であるとしてその証明書を登録することにより、アプリケーションをさらに保護できます。

5
Tom Squires

SSLは通信チャネルを保護します。

ログインに成功すると、暗号化された接続を介して認証トークンが発行されます。

認証トークンは、以降のすべてのリクエストでREST APIに渡されます。

1
CodeART

安全ではありませんが、秘密のコードやデジタル署名を追加することもできます。欠点:アプリに含まれている必要があります。これにより、自分が何をしているのかを知っていれば簡単に入手できます。

0
fNek

私の知る限り、HTTPSは、通信しているサーバーが本人であるかどうかを検証するためだけのものです。

実際、SSLを使用してクライアントとサーバーの両方を認証できます。または、「はい、クライアント証明書を使用できます」と言い換えます。

あなたがする必要があります...

  • 使用しているSSLライブラリを見て、モバイルデバイスでクライアント証明書を指定する方法を決定します。
  • コードを作成するか、HTTPSサーバーを構成して、信頼できる登録済みクライアントからの接続のみを受け入れるようにします。
  • 信頼できるクライアント証明書をサーバーに追加するメカニズムを考え出す
  • サーバーから信頼されなくなったクライアント証明書を削除するメカニズムを考え出す

モバイルアプリケーションに証明書をどこにでも保存させることができます。アプリケーション固有の認証が必要なため、保護されたディスクの場所に証明書を保存することを検討する必要があります(Androidでは、SQLiteデータベースに「config」テーブルを作成し、証明書の行と秘密鍵の行を作成できます) 。

0
atk