web-dev-qa-db-ja.com

セッションIDをCookieに直接保存することが安全でないのはなぜですか?

セッションミドルウェア について学習しています。

あなたsecretを提供する必要がありますまたはミドルウェアは不平を言います:

app.use(session({
  secret: "abc",
  resave: false,
  saveUninitialized: false,
  store: new MongoStore({
    mongooseConnection: mongoose.connection
  })
}));

調査を行ったところ、実際のセッションIDは

eKeYlF1DR6AtVkeFZK9vEIHSZT8e0jqZ

しかし、Cookieによると、セッションIDは

s%3AeKeYlF1DR6AtVkeFZK9vEIHSZT8e0jqZ.on5ifVE079C4ctKNdkNiJSh8NkQMckjd5fn%2FsxIQWCk

私は混乱しています。 セッションIDを直接Cookieに保存するのはなぜ安全でないのですか?セッションIDを直接保存できないのですか?

secretは秘密鍵であり、セッションIDは暗号化されているようですか?

私が理解しているように、攻撃者がこのCookieを(おそらくXSSまたはソーシャルエンジニアリングを介して)取得できる場合でも、攻撃者はセッションをハイジャックできます。 secretの意味がわかりません。

40
Angular noob

JSライブラリの作成者は、誤解を招くだけの十分な知識に基づいていますが、一般的であるが誤った仮定を行っているようです。

マジッククリエトフェアリーのほこりをまき散らして、チョコレートチップなどのセキュリティを強化することはできません。

著者が欠けているのは、いったんセッションIDに署名し、それをCookieに入れると、署名されたセッションID ISセッションIDです。つまり、文字通りエンドユーザーがサーバーにどのセッションであるかを通知する識別子サーバーが、実際のセッション識別子をセッションのメモリの内部表現に関連付けるための内部処理を行うことは問題ではありません。

明確に言うと、署名されたセッションIDが盗まれた場合-何らかの方法で、XSS、ソーシャルエンジニアリング、またはその他の方法で-攻撃者は、その署名されたセッションIDを使用して、ユーザーのセッションを内部でハイジャックすることができます。


つまり、ブラウザに送信する前にCookie値に署名することには、改ざん検出という名目上の利点が1つあります。つまり、ユーザーのCookieを受信すると、Webアプリケーションは、Cookieがbeforeで改ざんされていないことを確認できます。これを使用して、セッションメモリを検索します。つまり、署名を検証します。これにより、有効ではなかったセッションIDでのセッション検索を回避することにより、セッション管理に対する特定の高度な/アクティブな攻撃を防ぐことができます。

ただし、セッションIDは通常just idであり、セッション変数の検索に使用されるため、この想定される利点は疑わしいものです。また、セッションIDをターゲットとするmost攻撃は、これによって停止されません-セッションハイジャック、セッション固定、セッション寄付、セッションライディングなど...

とにかく、セッションCookieが使用前に改ざんされていないことを本当に確認したい場合は、デジタル署名よりも簡単な方法があります...

54
AviD

http://hueniverse.com/2015/07/08/on-securing-web-session-ids/ からのより完全な回答

免責事項:自分のシステムの詳細を知らない人からのセキュリティアドバイスと同様に、これは教育のみを目的としています。セキュリティは複雑で非常に特殊な領域であり、システムのセキュリティが心配な場合は、脅威の分析とともにシステムを確認し、適切なアドバイスを提供できる専門家を雇う必要があります。

強引な

ブルートフォース攻撃とは、攻撃者がさまざまな資格情報を使用してリクエストを繰り返し実行することでシステムにアクセスしようとする攻撃です(1つが機能するまで)。最も一般的な例は、ユーザーのパスワードを推測しようとする攻撃者です。これが、パスワードを長くし、推測を困難にするために辞書の単語を使用しないようにする理由です。適切に設計されたシステムは、失敗した認証要求を追跡し、攻撃が進行しているように見える場合は問題をエスカレーションします。

Web認証で使用されるクレデンシャルはパスワードだけではありません。最も一般的な実装には、認証が成功するとクライアントにセッションCookieを設定するログインページが含まれます。セッションCookieは無記名トークンとして機能します。トークンが表示されたユーザーは、認証されたユーザーと見なされます。セッションCookieを設定すると、すべてのページでユーザー名とパスワードを入力する必要がなくなります。ただし、このセッションCookieは唯一の認証キーとして機能するようになり、このキーへのアクセスを取得したすべてのユーザーがシステムにアクセスできるようになります。 Cookieは結局のところ、単なる文字列です。

セッションID推測攻撃は、ブルートフォース攻撃の一種です。攻撃者はパスワードを推測する代わりに、セッションIDを推測して認証Cookieを偽装しようと試みます。攻撃者はセッションIDを生成し、それらが実際のアクティブセッションと一致することを期待して、それらのIDを使用してリクエストを作成しようとします。たとえば、WebアプリケーションセッションIDが順番に生成された場合、攻撃者は自分のセッションIDを検索し、近くのセッションID値を使用してその偽造リクエストに基づくことができます。この攻撃から保護するには、セッションIDの推測を非現実的にする必要があります。 「不可能」ではなく「非実用的」と言っていることに注意してください。

非実用的

最初のステップは、セッションIDが十分に長く、非順次であることを確認することです。パスワードと同様に、セッションIDが長いほど、推測によって有効なIDを見つけることが難しくなります。また、カウンターなどの予測可能なアルゴリズムを使用してセッションIDが生成されないことも重要です。これは、そのようなロジックが存在する場合、攻撃者は推測せずにセッションIDを生成するためです。暗号で保護された乱数ジェネレータを使用して、十分に長いセッションIDを生成するのが、最も一般的な方法です。 「十分に長い」とは?まあ、それはあなたのシステムの性質に依存します。サイズは、有効なセッションIDを推測するための非現実的な努力に変換する必要があります。

攻撃者がセッションIDを推測できないようにするもう1つの方法は、セッションCookieにハッシュまたは署名を追加して、トークンに整合性を組み込むことです。 Expressセッションミドルウェアがこれを行う方法は、セッションIDとシークレットの組み合わせに対してハッシュを計算することです。ハッシュを計算するにはシークレットを所有する必要があるため、攻撃者はシークレットを推測する(またはハッシュを推測する)ことなく、有効なセッションIDを生成することはできません。強力なランダムセッションIDと同様に、ハッシュサイズは、保護対象の特定のアプリケーションのセキュリティ要件と一致する必要があります。これは、最後に、セッションCookieがまだ文字列であり、推測攻撃に対してオープンであるためです。

セッションIDは十分に長く、推測するのは非実用的でなければなりません。これを行うにはいくつかの方法があります。上記のランダム性とハッシュ手法は2つの最も一般的な方法ですが、唯一の方法ではありません。

レイヤー

強力なランダムセッションIDを生成する場合でも、ハッシュは必要ですか?絶対に!

コアセキュリティプリンシパルは階層化です。これは、すべての卵を1つのバスケットに入れないこととしても知られています。セキュリティの単一のソースに依存している場合、その単一のソースに障害が発生すると、セキュリティがまったくなくなります。たとえば、誰かがあなたの乱数ジェネレータにバグを見つけたらどうしますか?彼らがあなたのシステムのその部分をハッキングしてそれを置き換える方法を見つけたらどうなりますか?これを悪用する既知の攻撃は無数にあります。結局、それほどランダムではないことが判明した乱数の生成です。

整合性のために強力なランダムセッションIDとハッシュを組み合わせると、乱数ジェネレータの欠陥から保護されます。また、間違った乱数ジェネレーター関数を使用するなどの開発者のエラーからも保護します(たとえば、すべてのシステムが強力なメソッドとともに提供するそれほどランダムではないメソッド)。プロセスがどれほど優れていても、経験があっても、全員が悪いコードを書いています。これはソフトウェアエンジニアリングの一部です。このため、セキュリティを階層化することが非常に重要です。堀だけでは十分ではありません。堀の後ろにも壁が必要です。おそらく壁の後ろに警備員がいるでしょう。

誤ったランダム関数の使用やOpenSSLの深いバグが2つだけの問題であると思われる場合は、JavaScriptやその他の動的言語でのサルのパッチコードの一般的な慣行を検討してください。アプリケーションのデプロイメント全体のどこかに誰かがグローバルなランダム機能(テスト、ロギングなど)を乱して破壊した場合(または悪意のあるコードインジェクションの一部である場合)、ランダム性のみに依存しているセッションIDは安全ではなくなります。

警報

パスワードの推測とセッションIDの推測の重要な違いは、パスワードがアカウント(ユーザー名など)に関連付けられていることです。アカウントとパスワードのペアを使用すると、試行の失敗を比較的簡単に追跡できるため、ブルートフォース攻撃を追跡しやすくなります。ただし、セッションIDに関しては、セッションが期限切れになり、アカウントコンテキストが含まれないため、それほど単純ではありません。つまり、無効なセッションIDは、有効期限が切れたセッションまたは攻撃者からのものである可能性がありますが、追加のデータ(IPアドレスなど)がないと、大規模システムでの違いを見分けるのが困難になります。

(ハッシュまたは署名を介して)セッションIDに整合性コンポーネントを含めることにより、サーバーは、期限切れのセッション、割り当てられていないセッションID、無効なセッションの違いをすぐに認識できます。無効な認証試行のみをログに記録する場合でも(そうする必要があります)、有効期限が切れたセッションを無効なセッションとは異なる方法でログに記録する必要があります。違いを知るというセキュリティ上の価値に加えて、ユーザーの行動に関する有用な洞察も得られます。

衛生

資格情報は期限切れになるはずです。したがって、セッションIDには有限の有効期間が必要です(期間は非常にシステム固有の値です)。 Cookieには有効期限ポリシーが付属していますが、実際にそれを確実に遵守する方法はありません。攻撃者は、サーバーがそれを検出できなくても、Cookieの有効期限を任意の値に設定できます。一般的なベストプラクティスは、発行されるすべての資格情報にタイムスタンプを含めることです。これは、ランダムに生成されるセッションIDにタイムスタンプサフィックスを追加するのと同じくらい簡単です。ただし、このタイムスタンプに依存するためには、それが調整されていないことを確認できなければならず、それを達成する方法はハッシュまたは署名を使用することです。

セッションIDにタイムスタンプを追加すると、サーバーは、高価なデータベースルックアップを行わなくても、期限切れのセッションをすばやく処理できます。これはセキュリティとは無関係に聞こえるかもしれませんが、実際には安全なアプリケーションを維持するための非常に重要な部分です。

サービス拒否攻撃(またはDoS)は、サーバー上のリソースを消費しすぎてシャットダウンするか、他のユーザーがアクセスできないようにすることを唯一の目的として、攻撃者が繰り返し要求を行う攻撃です。すべてのリクエスト認証でアプリケーション層での完全なデータベース検索が必要な場合、攻撃者は偽造されたセッションIDを使用して簡単にDoS攻撃を仕掛けることができます。 cookieに整合性コンポーネントを含めることにより、サーバーはバックエンドのルックアップコストをかけずに、偽造または期限切れの資格情報を即座に識別できます。

緊急停止装置

時々物事がうまくいかない。そして、それらが非常にうまくいかない場合、セッションのクラス全体を即座に無効にする方法が必要です。ハッシュまたは署名を生成するにはサーバー側のシークレットまたはキーが必要なため、シークレットを置き換えるとすぐにすべてのセッションIDが検証に失敗します。異なるタイプのセッションIDに異なるシークレットを使用することにより、セッションのクラス全体を分離して管理できます。このようなメカニズムがない場合、アプリケーション自体が各セッションの状態について計算された決定を行うか、大量のデータベース更新を実行する必要があります。

さらに、地理的に異なる場所にデータベースを複製する大規模な分散システムでは、1つの場所のセッションレコードを無効にすると、複製に数秒から数分かかることがあります。つまり、システム全体が同期されるまで、セッションはアクティブなままです。自己記述型および自己検証型のセッションIDと比較すると、利点は明白です。

一般的用途

Expressセッションミドルウェアの重要な機能は、ユーザー生成セッションIDのサポートです。これにより、開発者は、完全に異なるプラットフォームに存在する可能性のある既存のエンティティーによってセッションIDが生成される既存の環境にミドルウェアをデプロイできます。ユーザー提供のセッションIDにハッシュを追加しないと、安全なシステムを構築する負担は、エキスパート(モジュール作成者)からユーザー(セキュリティ初心者である可能性が高い)に移ります。ハッシュの適用は、内部セッションIDジェネレーターを強制するよりもはるかに優れたアプローチです。

ワニ

強力なランダムセッションIDにハッシュを追加するだけでは、十分ではありません。堀がワニの恩恵を受けることができるかどうかは、やはり城特有の決定です。トピックから離れすぎずに、セッション管理層に追加できる他のレイヤーがたくさんあります。たとえば、2つのセッション認証情報を使用できます。1つは有効期間が長く(セッションと同じ長さ)、もう1つは有効期間が短い(数分または数時間有効)です。短命を更新するには長命を使用しますが、そうすることで、ネットワーク上で長命の資格情報が公開されることを減らします(特にTLSを使用しない場合)。

別の一般的な方法は、セッションの横にユーザーに関する一般情報(たとえば、名、最近表示したアイテムなど)を含む1つのCookieを用意し、そのCookieの一部をハッシュに含めて、ユーザーのアクティブ状態と認証。これは、「ユーザー名」をワークフローに戻す方法です。

さらに進むために、ハッシュを署名に置き換え、Cookieのコンテンツを暗号化することができます(その後、ハッシュまたは署名することができます)。セキュリティの冗長性は脅威と一致する必要があります。

19
Eran Hammer

NodeJSの yar セッション管理モジュールのメンテナーの1人であるEran Hammerは、この件について次のように述べています。

免責事項:あなた自身のシステムの詳細を知らない誰かからのセキュリティアドバイスのように、これは教育目的のみです。セキュリティは複雑で非常に特殊な領域であり、システムのセキュリティが心配な場合は、脅威の分析に沿ってシステムをレビューし、適切なアドバイスを提供できる専門家を雇う必要があります。

[...] 内部の整合性と検証のために署名なしトークンに署名することは、一般的なセキュリティ慣行です。エクスプレスセッションで十分なことは考えていませんが、最低限必要なことは確かです。

他の人のアカウントにアクセスするために、セッションを推測できるようにしたくない。 [...] インクルードによるセッションIDの推測の防止[sic]暗号化コンポーネント[sic]がこれを実現する正しい方法です。業界標準です。

セッションCookieは無記名トークンです。つまり、それらを持っている人はだれでも、正当な所有者としてフルアクセスを取得できます。リスクを減らすためにいくつかのことができるようにしたいと考えています。サーバー以外の誰かが有効な資格情報を発行できないようにすることは最低限であり、それが高速セッションで行われていることです。

私は単純な署名がセッション管理の十分な保護であるとは考えていません。そのため、このモジュール[yar]は iron エンコーディングを使用してコンテンツを暗号化し、整合性検証のために署名します。これにより、誰もが状態を調整することは事実上不可能になります(また、Cookie自体の状態を維持する機能が提供されます)。しかし、より重要なことに、資格情報の有効期限を設定できます。

Cookieには有効期限の指示が付属していますが、攻撃者は従う必要はありません。これは、誰かがCookieを盗んだ場合、そのCookieの有効期間を短くする方法がないと、システムが長時間公開されたままになることを意味します。 Cookieの有効期限ポリシーをサーバー側のポリシーと同期させることは、もう1つの複雑なレイヤーであり、システムのセキュリティプロファイルの一部であってはなりません。

他にも考慮すべき攻撃ベクトルがたくさんあります。たとえば、すべてのリクエストがセッションストレージルックアップをトリガーする場合、無効なセッションIDで [〜#〜] dos [〜#〜] を簡単に実行できます。リクエストが攻撃者からのものであることをすばやく検出する方法がある場合は、それをブロックするだけでなく、それと戦うための対策を講じることができます。無効なCookieの署名は悪意のあるソースからのみ発生する可能性があります(Cookieを生成する方法を変更した場合を除いて、Cookieを生成して処理できる場合)。

同じように、安全なシステムを維持するには、セッションIDが偽造されたのか、期限切れになったのかを判断できることが重要です。ランダムなIDを生成するだけの場合、それらが十分に長く、十分にランダムであると仮定すると、生成されたすべてのセッションIDを追跡しない限り、システムをスケーリングするのにコストと手間がかかるため、知る方法がありません。また、不正なCookieリクエストが攻撃者からのものであるかどうかを知りたい理由を明らかにすることは、かなり明白なはずです。

(コメント全体を表示)

したがって、基本的に、ランダムなセッションIDをCookieに直接保存することは必ずしも安全ではありませんが(IDが予測不可能で十分長い場合)、セッション情報の暗号化と署名により、追加の機能がいくつか提供されます(有効期限を保存する機能など) Cookie自体の情報、およびセッションIDを偽造する試みを識別する機能)を使用してセキュリティを向上させることができます。

特にexpressjsの場合、現在のメンテナも 次の理由を提供します

ユーザーは任意のセッションIDを使用できます。おそらく誰かがSQLデータベースからの自動インクリメント番号を使用する必要があると感じているかもしれませんが、それは問題ではありません。私たちは値に署名し、キーを引き延ばすことで、情報に基づいていない決定を保護します。

つまり、セッションIDに署名することで、ライブラリでセッションIDの生成をライブラリに処理させる代わりに、アプリケーションで予測可能または不十分な長さのセッションIDを(誤って)使用する可能性があるライブラリのユーザーを保護します。ユーザーが安全に選択されたセッションIDを使用している場合、明らかにこの理由は当てはまりませんが、このライブラリーはその仮定を行わないことを選択しました。

ハンマー この点を繰り返します

また、これは、幅広いユーザーをコア要件とする一般的なモジュールです。一部の人々はそれをうまく利用せず(たとえば、インクリメントID)、それに対応することを絶対に想定する必要があります。これは、幅広い対象者向けのモジュールを構築する際の一般的な方法でもあります。

14
Ajedi32