1

WebSocket を使用して EC2 インスタンスと通信します。スクリプトは nodejs と Express を使用して提供され、WebSocket を初期化します。現在、ELB が使用されているため、クライアント IP の識別が難しくなっています。x-forwarded-for ヘッダーを使用すると、HTTP のコンテキストで IP を取得できますが、サーバーの WebSocket コンテキストになると、Amazon によって転送されていないように見えます。

2 つのオプションを特定しました。

  1. (パブリック DNS を使用して) WebSocket をインスタンスと直接通信します。
  2. HTTP のコンテキストで IP を保存し、それをセッション ID に関連付ける、ある種のセッション ID を維持します。クライアント側は、HTTP 応答を使用してセッション ID を取得し、それを WebSocket で使用します。サーバーは、クライアントを識別し、キャッシュからその IP を解決します。

1 つはフォールト トレラントではなく、2 は複雑です。もっと解決策はありますか?Amazon はどうにかして IP を転送できますか? ベストプラクティスは何ですか?

ありがとう

4

2 に答える 2

1

私は Websocket と ELB を使用したことがありますが、それらを一緒に使用したことはありません。そのため、Elastic Load Balancer の HTTP フォワーダーが Websocket リクエストを理解していないことに気づきませんでした...

したがって、TCPフォワーダーを使用しているに違いないと思います。これは、別のポートを使用している理由を説明しています。もちろん、TCPフォワーダーはプロトコルを認識しないため、ヘッダーをまったく追加しません。

かなり一般的で単純に見えるオプションは、アプリケーションの http 側が、取得のために情報をキャッシュに格納するのではなく、情報をプッシュすることによって websocket 側に通知することです。環境に実装を困難または不可能にする障害物がないと仮定すると、スケーラブルで軽量です。

Websocket をロードする Web ページを生成するときに、文字列「ipv4:」とクライアントの IP (「192.168.1.1」など) を取得し、それらを連結して暗号化し、結果を URL フレンドリーにします。

/* pseudo-code */
base64_encode(aes_encrypt('ipv4:192.168.1.1','super_secret_key'))

128 ビットの aes を含むそのサンプル キーとそのサンプル IP アドレスを使用すると、次のようになります。

/* actual value returned by pseudo-code above */
1v5n2ybJBozw9Vz5HY5EDvXzEkcz2A4h1TTE2nKJMPk=

次に、websocket を含むページの html をレンダリングするときに、URL を動的に構築します。

ws = new WebSocket('ws://example.com/sock?client=1v5n2ybJBozw9Vz5HY5EDvXzEkcz2A4h1TTE2nKJMPk=');

Websocket からのクエリ文字列がコードにアクセスできると仮定すると、超秘密鍵を使用して、クエリ パラメーター "client" で見つかった文字列を base64_decode してから aes_decrypt し、"ipv4:" で始まることを確認できます。そうでない場合、それは正当な値ではありません。

もちろん、"ipv4:" (文字列の先頭) と "client" (クエリ パラメータ用) は任意の選択であり、実際の意味はありません。128 ビット AES の選択も恣意的でした。

もちろん、このセットアップの問題は、リプレイの影響を受けることです。特定のクライアント IP アドレスは常に同じ値を生成します。クライアントの IP アドレスを「情報目的」 (ロギングやデバッグなど) にのみ使用する場合は、これで十分な場合があります。より重要なことに使用している場合は、タイムスタンプを追加するなどして、この実装を拡張することをお勧めします。

'ipv4:192.168.1.1;valid:1356885663;' 

受信側で、文字列をデコードし、タイムスタンプを確認します。安全と思われる秒間隔が +/- でない場合は、信頼しないでください。

これらの提案はすべて、websocket url を動的に生成する能力、それに接続するブラウザの能力、および websocket リクエストで URL のクエリ文字列部分にアクセスできるかどうかにかかっています...しかし、これらの部分がうまくいく場合は、たぶんこれが役立つでしょう。


追加の考え (コメントから):

上で提案したタイムスタンプはエポックからの秒数です。これにより、プラットフォームでステートフルネスを必要としないインクリメント カウンターが得られます。必要なのは、すべてのサーバー クロックが正しいことだけです。したがって、不要な複雑さを追加することはありません。復号化された値に含まれるタイムスタンプが (たとえば) サーバーの現在の時刻との差 (+/-) 5 秒未満の場合、認証されたクライアントを扱っていることがわかります。許可される時間間隔は、元のページをロードした後にクライアントが Websocket 接続を試行するのに妥当な最大時間に、すべてのサーバー クロックの最大スキューを加えた長さである必要があります。

もちろん、NAT を使用すると、複数の異なるユーザーが同じ送信元 IP アドレスの背後にいる可能性があります。また、可能性ははるかに低いですが、ユーザーが最初の http 接続を開始したソース IP とは異なるソース IP から実際に Websocket 接続を確立し、それでも非常に正当である可能性があることも事実です...認証ユーザーは、実際の送信元 IP よりも重要な値になる場合があります。

暗号化された文字列内に認証されたユーザーの ID も含めると、オリジン IP、ユーザー アカウント、および時刻に固有の値が 1 秒の精度で得られます。これはあなたが追加の塩で言及しているものだと思います。ユーザー アカウントを文字列に追加すると、必要な情報が得られます。

'ipv4:192.168.1.1;valid:1356885663;memberid:32767;' 

TLS は、この暗号化された文字列が権限のない第三者によって発見されるのを防ぐ必要がありますが、生成された URL は、ユーザーのブラウザーの HTML ページの「ソースの表示」でクリア テキストで使用できるため、再生可能性の回避も重要です。今日は許可されているが、明日は許可されていないユーザーが、もはや有効ではないと認識される必要がある署名付き文字列でなりすましできるようになることは望ましくありません。タイムスタンプにキーを設定し、非常に小さな有効なウィンドウに収まるように要求すると、これを防ぐことができます。

于 2012-12-30T16:55:34.147 に答える
0

それは、アプリケーションがどれほど深刻かによって異なります。

クライアントの IP アドレスに基づいてあらゆる種類の決定を行うことは、危険な提案です。それに基づいてセキュリティを構築すると、なおさらです。これまでに提供された提案は、与えられた制約内でうまく機能しますが、堅牢なエンタープライズ アプリケーションには十分ではありません。

すでに指摘したように、クライアントの IP アドレスは NAT によって隠蔽される可能性があります。そのため、職場から Web にアクセスする人々は、多くの場合、同じ IP アドレスを持っているように見えます。自宅のルーターは NAT として機能するため、自宅で Web にアクセスしている家族全員が同じ IP アドレスを持っているように見えます。または、同じ人が PC とタブレットからアプリケーションにアクセスしていても...

NAT の背後にあるかどうかに関係なく、同じマシン上の 2 つのブラウザーからアプリケーションを使用すると、同じアドレスを持つように見えます。同様に、同じブラウザ内の複数のタブは、同じアドレスを持つように見えます。

プロキシやロード バランサなどの他のジャンクション ポイントも、元のクライアント IP アドレスを隠して、プロキシ/ロード バランサの背後にあるものがクライアントであると認識している可能性があります。(より洗練された、またはより低レベルの仲介者はこれを防ぐことができます。これが、仲介者をより洗練された、または高価にする理由です。)

上記のすべてを考慮すると、重要なアプリケーションは、特にセキュリティに関する重要な決定をクライアント IP アドレスに依存するべきではありません。

于 2013-01-01T22:43:35.347 に答える