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


96

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

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

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

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

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

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


HTTPSはSSL(およびTLS)を使用します。SSL / TLSはクライアント認証で使用できます。
atk

クライアント側のSSL証明書ですか?私はそれが私が探しているものだと思いますが、モバイルアプリケーション(AndroidとiOS)でもそれが可能かどうかわからないのですか?クライアント証明書はどこに保存されますか?デバイスストレージ、メモリ?
スーパーセル

SSLは、モバイルアプリケーションではなく、モバイルデバイスのみを認証します。
モロン

@スーパーセル:回答を追加します
atk

回答:


48

できません。

エンティティ、エンティティ、人、ハードウェアクライアント、またはソフトウェアクライアントを検証することはできません。あなたは彼らがあなたに言っていることが正しいことを確認し、それから正直になります。

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

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

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

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

参照:AndroidアプリケーションのSSL証明書検証の無効化

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


1
OSによって暗号化されたドライブに証明書が保存されているハードウェアでクライアント証明書を使用しました。しかし、そこであっても、誰もそれが絶対確実だとは信じませんでした。目標は、カジュアルなユーザーにとっては難しくすることでした。
スティーブンバーナップ

1
@Morons:webappはこれを解決しますが、ユーザーはwebappよりもネイティブアプリを使用する可能性が高いと思います(仮定が間違っている場合は修正してください)。これが非常に重要である理由は、APIがユーザーにデータベースの一部へのアクセスを提供するためです。データベースには、数か月の作業を通じて収集した多くのデータが含まれています。他の企業やユーザーが自分の目的で簡単に使用できるデータです。クライアントを保護しなければ、誰がそれを使用していたのかわかりません(私たちに対して)。
スーパーセル

6
webappは問題を解決しません。Webアプリケーションのクライアント側を変更して、必要な処理を実行するのは非常に簡単です。
スティーブンバーナップ

5
@Supercell誰かのデータを表示して、そのデータの共有を停止することはできません。一部の人がデータを持ちたくない場合は、彼らにそれを見せないでください。
モロン

同意しますが、理由は異なります。en.wikipedia.org/wiki/SecurIDのようなrsaのようなデバイスを制御できていれば、ちょっとできます。ただし、モバイルは制御できるものではありません(プラグインキーなどの添付ファイルを受け入れることができます)。
imel96

31

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

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

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

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

例えば、想像GETの要求を/products/widgets

クライアントシークレットが「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分以内)

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


6
このハッシュメカニズムは、プログラマーがapkを逆アセンブルするときに理解できます。
プニスラージ

8
@PunithRaj、それについては2番目の段落で説明しました。「誰かがクライアントをリバースエンジニアリングし、REST APIを悪用しないことを保証することはできません。しかし、偶然の試みの前に障壁を置くべきです。」
Carson63000

警告については、サーバーとモバイルでUTCを使用していますが、これは問題を解決しますか?
shareef

@ Carson63000-それで、具体的な解決策はありますか?特に、ユーザー登録APIは公開されている必要があり(ユーザーはWebまたはモバイルアプリにログインする前に登録する必要があります)、ボットの標的となって数千の偽ユーザーを作成できます。
Tohid

17

興味のある方は、Androidで、取得したリクエストがアプリから送信されたことを確認できます。

つまり、アプリをGoogleにアップロードすると、自分(およびGoogle)だけが知っている一意のキーでアプリに署名します。

検証プロセスは、次のようになります。

  1. アプリがGoogleにアクセスして認証トークンを要求する
  2. アプリはトークンをバックエンドに安全に送信します
    1. バックエンドはGoogleにアクセスし、アプリから取得した認証トークンを確認します。
    2. バックエンドは、アプリが署名した一意のキーが一致するかどうかを確認します。一致しない場合は、アプリではなかったことを意味します...

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


1
良い答えですが、悪意のあるユーザーは十分な労力でアプリを偽造できます。しかし、本当に安全なものは何もありません。それは、問題ではなく、いつの問題なのか
mateos

1
:iOSのために、このオプションがありますリンク もDeviceCheck APIを使用すると、あなたが受け取るトークンはアプリがダウンロードされた本物のAppleデバイスから来ていることを確認してみましょう
Iwaz

アカウント(メール)が必要です
user25

5

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

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


5

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

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

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

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

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

トークンを返します。トークンは、APIへの信頼性の証明として送信できます。

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

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


0

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

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

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


1
いくつかの追加情報を追加しました。あなたが言ったように、アクセストークンで認証を行うつもりでした。REST APIでは、特定のアクションについてのみ、ユーザーがログインする必要はありません。どちらの場合も、クライアントは署名/信頼される必要があります。
スーパーセル

ネイティブのモバイル開発についてはあまり知りませんが、モバイルアプリケーションはREST APIにモバイル番号を提供できますか?Androidフォンにアプリをインストールするとき、アプリに特定の許可を与えるようによく求められます。セキュア接続を介してすべてのリクエストでモバイル番号を送信できる場合、不明なモバイル番号を持つすべてのリクエストを拒否できます。ただ...大声ここに考えて
CodeART

これは機能しますが、ユーザーがログインし、ユーザーアカウントにバインドされた番号が必要になります。そうしないと、サーバーは番号を検証する対象を何も持ちません。
スーパーセル

モバイルアプリケーションをどのようにインストールしますか?
-CodeART

彼らは、アプリケーションストア(グーグル、アップル、マイクロソフト)を介して利用できるようになります
スーパーセル

0

安全性はあまり高くありませんが、何らかのシークレットコードやデジタル署名を追加することもできます。欠点:アプリに含まれている必要があります。これにより、何をしているのか知っている場合に簡単に入手できます。


0

私の知る限り、HTTPSは、通信相手のサーバーが本人であることを検証することのみを目的としています。

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.