web-dev-qa-db-ja.com

APIが改ざんされないように保護しますか?

JSONを介してデータをシリアル化するwebsocketでAPIを構築しています。アプリ自体はチャットアプリケーションです。私はデータを送信するために次の構造を考え出しました:

{date: '2020-05-31', time: '14:28:05', text: "Hey!", to: '<id:int>', from: '<id:int>'}

ユーザーは基本的にブラウザを介してメッセージを送信し、これはWebSocketサーバーで受信されます。 from: 'id'はデータを送信しているユーザーからのものであり、to: 'id'はデータが送信されているユーザーのものです。

これを見て、私は非常に悪い感じがあります。私の考え;アプリを使用しているユーザーは理論的には認証を行い、そこでIDを取得します。次に、受信者は別のIDを持つことになります。これは、認証されたIDとは異なります(明らかに)。サーバーはそのIDを探してメッセージを送信しますが、これが安全かどうかはわかりません。

攻撃者からアプリを保護するために正しく対処する必要があると思ういくつかの側面があります。

  • 攻撃者が "from:id"を改ざんして、任意のユーザーからだれかに任意のメッセージを送信できるようにした場合はどうなりますか?
  • 攻撃者が"to:id"フィールドを利用して何百万ものメッセージをスパムするスクリプトを作成するとどうなりますか?

私が気にしていない別のセキュリティ問題がある可能性はありますか?

22
VladiC4T

攻撃者が「from:id」を改ざんして、任意のユーザーからだれかに任意のメッセージを送信できるようにした場合はどうなりますか?

セッションを作成し、ユーザーIDを直接使用するのではなく、セッションIDをIDとして使用します。例えば。ユーザーに資格情報を送信させ、検証が成功すると、(有効期間が短い)セッションハンドルを返します。これは、今後のメッセージで使用できます。

セッションが存在し、アクティブであることを確認し、それをユーザーのサーバー側にマッピングします。

攻撃者が「to:id」フィールドを利用して何百万ものメッセージをスパムするスクリプトを作成した場合はどうなりますか?

ユーザー側のサーバー側のレート制限。たとえば、1分あたり10人を超えるユーザーへのメッセージ送信を禁止します。これはおそらく正当なユーザーを悩ませませんが、スパマーの努力を妨げます。制限の調整が明らかに必要な場合があります-動作に基づいて信頼できるユーザー向けに引き上げ、ユーザーからスパムに関するレポートを受け取ったらそれを引き下げることが考えられます。

51
vidarlo

基本的に、ユーザーからのすべての入力を潜在的に悪意のあるものとして扱う必要があります。

Vidarloはすでに2つのセキュリティ問題とそれらの答えでどのようにそれらを防ぐことができるかについて述べました。

また、コンテンツ自体( "text:")に悪意のあるコード(javascriptスニペットなど)が含まれている可能性があることも付け加えておきます。このコードが受信側で実行されていないことを確認してください。

また、時刻が正しいかどうかも確認します。アプリケーションによっては、タイムスタンプを検証することが役立つ場合や必要な場合さえあります。

13
Lukas

攻撃者が「from:id」を改ざんして、任意のユーザーからだれかに任意のメッセージを送信できるようにした場合はどうなりますか?

APIではfrom:idを使用しないでください。あなたはすでにユーザー認証セッションからそれを知っていて、そもそもユーザーがそれをあなたに送信する理由はありません。送信するものがなければ、改ざんするものはありません。

そのメモでは、日付と時間も捨ててください。メッセージをいつ受信したかはすでにわかっているので、ユーザーに通知する必要はありません。アプリケーション+ APIにオフライン/スケジュール/バックログメッセージの概念がある場合にのみ必要です。

攻撃者が「to:id」フィールドを利用して何百万ものメッセージをスパムするスクリプトを作成した場合はどうなりますか?

これはかなり古く、古いソリューションと同じように、異なる古典的な問題です。最も単純なものの1つは、タイムアウトを導入することです。バックエンドは、使用がメッセージを送信したことを記憶しており、一定期間が経過するまで何も送信できません。さらに複雑な解決策は、ユーザーを一定期間の一定量のメッセージに制限することに要約されますが、より多くのメッセージが送信されるにつれて、時間とともに減衰する次第に大きくなる遅延を使用します。例とアイデア。

12
Oleg V. Volkov

これらの問題への取り組み方について、もう少し別の見方を示します。認証とセッション管理が適切に実装されていることを前提としています。

攻撃者が「from:id」を改ざんして、任意のユーザーからだれかに任意のメッセージを送信できるようにした場合はどうなりますか?

作成時に各「チャットルーム」に一意の(長い、ランダム、推測が非常に難しい、セッションIDなど)識別子を生成し、すべての関係者がそのチャットルームに参加できることを確認した場合は、代わりにそれを使用できます。ユーザーIDと、各ユーザーがメッセージを送信できるチャットルームを制御して、他のユーザーが他のユーザーのプライベートチャットにコンテンツを送信できないようにします。したがって、ユーザーXとユーザーYからのメッセージはチャットルームAに発行され、アプリケーションはそれらを送信します。ユーザーZは許可されていないため、アプリケーションはメッセージを渡すことを拒否します。

攻撃者が「to:id」フィールドを利用して何百万ものメッセージをスパムするスクリプトを作成した場合はどうなりますか?

メッセージがユーザーIDに宛てられないようにし、ユーザーIDを推測しにくくするようにしてください。

2
Pedro

攻撃者が「from:id」を改ざんして、任意のユーザーからだれかに任意のメッセージを送信できるようにした場合はどうなりますか?

別のオプションは、各ユーザーに公開鍵と秘密鍵のセットを提供することです。これらは、コンテンツが改ざんされておらず、指定されたユーザーから発信されていないことを確認する各メッセージの署名を生成するために使用できます。

ユーザー1がユーザー2にメッセージを送信したいとします。簡単なプロセスは次のようになります。

  • ユーザー1には公開鍵と秘密鍵のペアが与えられます。彼ら(またはサーバー)はpublicキーを他のユーザーに公開します。
  • ユーザー1はメッセージの内容を作成し、独自のprivateキーを使用してその署名を生成します(この秘密を保持します)
  • ユーザー1は、次のようなパケットでメッセージを送信します
{ "Signature": "kA7dagf4...", Content: {date: '2020-05-31', time: '14:28:05', text: "Hey!"...
  • ユーザー2はメッセージを受信し、ユーザー1のpublicキーを使用して、メッセージの内容が署名と一致することを確認します

重要なことは、公開鍵は署名の検証にしか使用できないことです。秘密鍵なしで署名を作成することはできません。

ユーザー1になりすましてユーザー2にメッセージを送信しようとする悪意のある俳優は、ユーザー1の公開鍵によって検証される署名を作成できないため、これを行うことはできません。したがって、ユーザー2は署名が無効であることを確認し、メッセージを受信したときにメッセージを拒否できます。

これがおおよそのJSON Web Tokenの仕組みです。詳細については、これを参照することをお勧めします https://jwt.io/introduction/

攻撃者が「to:id」フィールドを利用して何百万ものメッセージをスパムするスクリプトを作成した場合はどうなりますか?

以前の回答で述べたように、レート制限とto:idおよびfrom:idフィールドを推測しにくくする組み合わせ。

2
Barker1889

明らかなのは、データが暗号化されていないことです。 完全性のない暗号化は依然として攻撃の余地を残しているため、改ざんについてはすでに言及しており、多くの場合、暗号化と完全性は同時に対処されます

データのMAC(メッセージ認証コード)を追加します。 GCM(Galois/Counter Mode)のようないくつかの暗号化モードには1つが含まれており、他の暗号化モードは個別であるため、HMACを他の何かと一緒に使用できます。 1石で2羽の鳥を殺すか、2石を使用します。これにより、APIの攻撃からユーザーを保護できますか?自分が危険にさらされた場合に何が起こるかについて考える必要があります。

他の種類のAPIを見て、それらがどのようにして攻撃の種類を軽減したかを確認することもできます。たとえば、OAuth 2は、 異なる理由 のために、状態パラメーターとノンスを使用します。@ vidarloの回答と同様に、 nonceをセッションIDと組み合わせて使用​​できます。

1
Iain

あなたのアプローチには数多くのセキュリティ問題があり、ほとんどはすでに他の回答で指摘されています。

これらの問題を自分で見つけるのに役立つ一般的な原則でお答えしたいと思います。

ユーザーが入力したすべてのデータを悪意のあるものとして扱う

クライアントから来るものはすべて信頼されていません。入力の検証、トリミング、エスケープ、9ヤード全体が必要です。あなたの場合、あなたのappはおそらく適切なJSONを送信しますが、誰かがJSONを手作りして無効なJSONを与えた場合、APIで何が起こるのでしょうか? t文字列を終了するか、そこにSQLインジェクションを混在させますか?

既存のデータを入力しないでください

他の回答で指摘されているように、あなたはすでに日時と「from」IDを知っているので、それらを入力として受け入れないでください。一般に、信頼できるソースから入手できるものについては、入力を受け入れないでください。

迅速なアプローチ

すべての要素を確認し、「何が問題になる可能性があるのか​​」を自問してください。 Swift( here または他のいくつかのソース)は、構造化された方法です。基本的に、入力をテキストとto-IDに減らしたら、誰かが間違ったデータを送信したり、データが少なすぎたり、多すぎたりする可能性はありますか?このアプローチにより、列挙、フラッディング/スパムなど、他の回答で概説されている脅威に到達するはずです。

バックエンドシステムを検討する

最後に、バックエンドシステムの弱点を理解します。 SQLデータベースが背後にある場合は、SQLインジェクションの可能性があるかどうかを検討してください。また、パフォーマンスとシステムの制限についても考慮してください。ユーザーが潜在的に大量のデータを送信して、I/O、処理、またはストレージ容量を圧倒する可能性はありますか?彼は他のユーザーのAPIをブロックできますか(並列処理の制限は何ですか?処理できる接続の数など)。

これは完全な脅威モデリング手法ではありませんが、少しの努力で90%の効果があることがわかります。

1
Tom

ルール0:クライアントを信頼しないでください。すべての状況でクライアント側からのすべての入力を検証します。

この場合、これは、送信側ユーザーが(a)メッセージを送信していると主張するユーザーとして認証されていること、および(b)基準に基づいて、特定のメッセージの送信が許可されていることを確認することを意味します。また、「テキスト」フィールドを保存または誰かに表示する前にサニタイズする必要があり、送信時刻のタイムスタンプをサーバーで設定する必要があることも意味します。システムに関する限り、メッセージが「送信」された場合のみシステムは送信者からそれを受信しました。

サーバーがユーザーのために入力できる(および入力する必要がある)モデルの部分をトリミングした後、実際に持っているのは受信者IDとメッセージの内容だけです。

シーケンシャルIDやスパミングを使用してユーザーリストを列挙することに関する懸念に関しては、ユーザーのアクセスを制限する「メール、電話、ユーザー名などによる」「友達リクエスト」システムなど、複数の方法で対処できます。事前に許可された受信者にメッセージを送信でき、友達リクエストのターゲットがシステム内の実際のユーザーであるかどうかは示されません。さらに、リーキーバケットのようなもので従来のレート制限を実行したり、フラッド/スパムの動作を示しているユーザーにフラグを立てたり、禁止したりする監視システムを構築することもできます。

0
Garandy