私はPHPでセッション管理クラスに出会いました。これはセッションストレージフォルダー内のセッションデータを暗号化します(つまり、/tmp
)であり、後でスクリプトを使用してキーを使用して復号化できます。本当に必要なのかしら?次のような(単純化された)例のようなセッション乗っ取り防止をすでに実行している場合:
session_start();
if (isset($_SESSION['fingerprint']))
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'].'SECRETSALT'))
exit; // Prompt for password
else
$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'].'SECRETSALT');
セッションデータを暗号化する必要がありますか?または、セッションを介して機密情報(個人情報、CC番号、資格情報など)を保存する場合にのみ暗号化が必要ですか?
さらに、次のような簡単な方法でユーザーがログインしているかどうかを検証している場合:
// login.php
if ($_POST['password'] == $db_password)
{
$_SESSION['logged_in'] = true;
redirect_to_protected_area();
}
else
// show login again
// protected_area.php
if (!isset($_SESSION['logged_in']) OR !$_SESSION['logged_in'])
exit; // Prompt for password
else
// show protected area
セッションデータが暗号化されておらず、ハッカーがデータを簡単に見た場合(つまり、指紋のmd5ハッシュとlogged_in = true
)。彼は実際にログインできますか、それとも最初にmd5を「クラック」する必要がありますか?
注:md5は例を簡略化するために使用されましたが、実際にはより優れたハッシュアルゴが使用されています。
PHPでセッションデータを暗号化することは、車をロックして鍵を屋根に置いたままのようなものです。適用される脅威シナリオを検討してください:
最初のシナリオでは、攻撃者はサーバーへのアクセス権を取得する必要があり、その後、特権をrootに昇格させるか、セッションデータディレクトリを所有するユーザーに偽装します(例:Apacheの場合はwww-data
、nginxの場合はnobody
) 。これらのディレクトリには、所有者以外のユーザーがデータにアクセスできないようにするアクセス制御(通常は0600
権限ビット)が適用されています。
攻撃者がサーバーへのアクセス権をすでに持っており、Webサーバーデーモンが実行されているユーザーになりすますことができる場合、攻撃者は定義上、Webサーバープロセスがアクセスできるすべてのデータにアクセスできます定義は、Webサーバーまたはその下で実行されているコードが使用している可能性のあるすべての暗号化キーにアクセスできます(ただし、HSMは例外ですが、妥当ではありません)ここで1つが使用されることを想定しています)。
つまり、攻撃者がセッションデータファイルを読み取ることができる場合、暗号化キーも読み取ることができるため、セッションデータを復号化できます。暗号化は、せいぜい難読化になるだけです。
2番目のシナリオでも同じ問題が発生します。キーがセッションデータと共にハードディスク上にある場合、攻撃者はキーを読み取ってセッションデータを復号化するだけです。この問題を解決する方法は、キーがディスクに保存されないようにセッションデータを暗号化することです。正しいアプローチは、フルディスク暗号化(FDE)を使用し、ブート時にout-ofを使用して手動でパスワードを入力することです。バンド管理(iLO、DRAC、リモートKVMなど)により、全体ハードディスクが暗号化されないように暗号化されます。攻撃者は、ディスクが盗まれた場合、ディスク上の任意のデータにアクセスすることができます。
ただし、このシナリオでさえ、FDEはセッションデータの保護という点ではセキュリティ上の利点はそれほど大きくない場合があります。その理由は、ほとんどのプラットフォームと構成で、セッションデータはtmpfsボリュームによってバッキングされている/tmp
に格納されるためです。 tmpfsの重要な点は、それが揮発性であること(つまり、再起動時にデータが失われること)であり、ほとんどの場合、内容はRAMに保存されます。しばらく触れられていないデータはディスクにスワップアウトされる可能性があります。これは、FDEdoesがセッションデータを保護するという利点を提供しますが、これが発生する前に、古いセッションが期限切れになるということです。そうは言っても、FDEは他のタイプのデータ盗難(インフラストラクチャの資格情報、SSL証明書の秘密キーなど)から保護するため、優れたセキュリティプラクティスの一環としてすべてのシステムでFDEを使用することをお勧めします。
PHPでセッションデータを暗号化するsome意味がある唯一の状況は、セッションデータがデータベースまたはキーに保存されている場合です。バリューストア。このシナリオでは、セッションデータはおそらく不揮発性(つまり、ディスクに格納される)であり、攻撃者が侵害する状況mightがあることを期待する必要がありますデータベース(見落とされたphpMyAdminインスタンスに入るなど)はファイルシステムではありません。このような場合、キーはファイルシステム上にあり、攻撃者はアクセスできません。ただし、これは非常にまれなケースです。
私がよく聞くもう1つの主張は、特定のデータはコンプライアンス上の理由で暗号化する必要があるということです。 PCI-DSSでのPANデータ。ここでのソリューションは正確なシステムアーキテクチャに依存しますが、一般的に言えば、セッションデータにデータをまったく保存しないか、外部ブローカー/ HSMを使用してデータを暗号化/復号化してキーを分離するか、単に保管中のデータのoffline暗号化のみが必要な場合は、FDEを使用します。
上記で説明した理由で一般的にはお勧めしませんが、何らかの理由でPHPでセッションデータを暗号化するように設定されている場合、実際にはPHP $_SESSION
のすべての使用を変更せずに。 SessionHandler class を使用して、セッションの通常の処理をオーバーライドできます。ドキュメントは、セッションデータを暗号化する方法の簡単な説明を提供します。
ただし、セッション全体でキーを作成および保存する方法が必要です。明らかに、これはセッションマネージャー自体では実行できません。それ以外の場合は、暗号文でキーを配布することになります。私の提案は [〜#〜] apc [〜#〜] または memcache などのメモリ内キャッシュを使用することです。ここで、キャッシュ内のキー名はセッションID。
適切なWebフレームワーク(中途半端なデザインのWebフレームワーク)を使用している場合は、セッションデータを暗号化する必要はありません。それは本当にフレームワークの責任であるべきです。
ただし、PHPを使用している場合は、適切なWebフレームワークを使用していません。 PHPは、非常に多くの点でセキュリティの問題の子です。これらの方法の1つは、デフォルトで、セッションデータを_/tmp
_に格納することです。一部の共有ホスティングサービスでは、_/tmp
_がユーザー間で共有される場合があります。したがって、PHPは、他のユーザーが許可なしにデータを表示できる場所にセッションデータを格納しています。これは悪い設計上の欠陥です-でも、PHPは悪い設計上の欠陥でいっぱいです。それがPHPのある生活のようなものです。
したがって、共有ホスティングサービスでPHPを使用している場合(_/tmp
_は他のユーザーがアクセスできます)、はい、セッションデータを暗号化する必要があります。これを行う1つの方法は、 (session_set_save_handler()
フックを使用してセッションデータを暗号化する です。強力な暗号化(認証された暗号化を使用し、一般的な暗号化の落とし穴を避ける)を使用して、適切なキー管理を確実に行ってください(暗号化キーを_/tmp
_または共有ホスティングサービスの他の顧客ができる他の場所に保存しないでください)。それを参照してください)。
または、専用マシン(専用仮想マシン、VPS、専用物理マシンなど)でPHPアプリケーションをホストし、信頼できないユーザーにそのマシンへのログインを許可しないでください。または、機密情報をセッションストアに保存しないことに何らかの自信がある場合は、セッションデータを暗号化する必要はありません(ただし、他の誰かが機能を追加するのは簡単であるため、メンテナンス中は脆弱です)将来的には、セキュリティの影響を認識せずに、セッションストアに機密情報を追加する可能性があります)。
しかし、実際には、より良い答えは、真剣に設計されたWebフレームワークを使用することです。友人は、友人がセキュリティクリティカルな問題のために裸のPHPを使用することを許可しません。たとえば、 このトピックに関するJeff Atwoodのブログ投稿 を参照してください。
キーがサーバー側に保存されている場合はあまり意味がありませんが、キーはブラウザまたはユーザーから取得される可能性があります。このシナリオでは、サーバー/ソースコードにアクセスしても、SSLを使用してキーにアクセスすることは困難です。
セッションデータはファイルシステム/データベースに保存される可能性があるため、バックアップに保持されます。また、共有システムでは、構成方法に応じて、セッションデータに詳細なセキュリティが提供されます-1つのユーザーアカウントが1つのサイトにマッピングされる場合、ssh/ftpアクセスを制限するのは簡単ですが、PHPのアクセスを特定のディレクトリツリーに制限しますもう少し複雑です(open_base_dirを回避する方法はいくつかあります)。ローエンドホスティングの場合、各Webサーバーを各サイトの個別のuid /個別のFPMグループとして実行しても、経済的に意味がありません。
そのようなシステムにクレジットカードの詳細を保存するのは正しい考えではありませんが、他のサービスをときどき呼び出すための単純なフロントエンドが必要な場合はどうでしょうか。 sshを介した別のサーバーの可用性/パフォーマンスのポーリング、SMSの送信、またはメールボックスへのアクセス?これらの場合、セッション内に一時的にセカンダリ認証トークン/暗号化キー/リモートセッション識別子を保持する可能性があります。
PHP srcファイルへの書き込みアクセスをwebserver uid以外の少数のユーザーotherに制限するのは簡単ですが、webserver uidはセッションデータを書き込むことができる必要があります。ユーザーが認証されると、通常、承認はセッションに格納された認証済みユーザーIDに基づいて行われます。したがって、これはpartのように、特権の昇格から保護するソリューションになります(投稿に記載されていない他のコンポーネントが必要です)。
キーの管理方法に応じて、セキュリティに役立ちます一部のEdgeの場合。
Cookieを使用してセッションIDのみを保存する方が簡単です。次に、サーバーは、どのユーザーがどのセッションに属しているか、および各ユーザーがどの権限を持っているかを記憶する必要があります。この設計には、すべてのアプリケーションインスタンス間でセッションデータを通信する必要があるため、ロードバランシングの効果が低くなるという欠点があります。
より良い設計は、ログインノードに認証を実行させ、データベース内のユーザー権限を検索させることです。このデータは、暗号化されたトークンとしてクライアントに返され、CookieまたはURLに格納できます。暗号化はトークンの改ざんを妨げないため、このトークンへの署名が必要です。この場合、各サービスが署名を検証してから処理することが重要です。これは実際には JSON Web Tokens の間の中心的な考え方です