web-dev-qa-db-ja.com

エラーメッセージでパスワードを明らかにする必要がありますか?

PHPのPDOクラス を使用してペットピートを作成しています。警告の注記を見るとわかるように、例外がキャッチされなかった場合、デフォルトでデータベースのパスワードが表示されます(表示エラーが発生している場合、初心者のWebマスターが本番サーバーで起こりそうな状況です)。

PHP Dev

私:

MySQL自体がデバッグまたはエラー発生時にパスワードを隠すため、パスワードを明らかにすることは非常にまれです。たとえば、MySQLの典型的な出力は「ユーザー 'root' @ 'localhost'のアクセスが拒否されました(パスワード:YESを使用)」ですが、パスワードは明らかになりません。

私たちが知っているように、PDOに依存するサードパーティのソフトウェアを使用する多くの初心者プログラマーまたはエンドユーザーは、display_errorsがオフになっていても気にしないでしょう。

これはセキュリティ上のリスクだと思います。たとえば、悪意のあるユーザーがスパイダーを実行して、「致命的なエラー:キャッチされていない例外 'PDOException'」という文字列を含むWebサイトを検索すると、パスワードを取得できます。

ぜひご検討ください。

PHPコア開発:

はい、display_errors = onで運用サーバーを実行し、引数を付けてバックトレースを出力することはセキュリティ上のリスクがあります。だから絶対にやらないでください。

PHP Core Devは、エンドユーザーにエラー表示をオフにすることをむしろ望んでいるようです。警告を与えたとしても、MySQL自体(1つのPDOが抽象化しているため、 )はパスワードを公開していませんが、PDOはそれを公開することを好みます。

PHP Core Devsはエラー時にパスワードを明かすのが正しいと思いますか?

32
IMB

この質問は読み込まれますが、私は答えに完全に同意します。いいえ、パスワードはエラーメッセージで明らかにされるべきではありません。ユーザーの明示的な同意なしに、パスワードをどこにも書き出さないでください。次の役割と、ユーザーが入力したばかりの間違ったパスワードにどのようにアクセスするかを検討してください。

  • ユーザー。それは、彼女が今入力した内容を知ることができる唯一の役割です。いいね.
  • 誰かがショルダーサーフィンをしている。ほとんどのパスワード入力フォームでは、パスワードを****に隠すことができます。画面にパスワードを表示すると、この保護が無効になります。パスワードが本番環境に表示されていない場合は関係ありません(ただし、これについては以下で詳しく説明します)。
  • パスワードがあったシステムの管理者。悪意のある管理者は、通常、いくつかの不正なログコードを挿入することでパスワードを取得できますが、これはアクティブな攻撃であり、検出されるリスクがあります。パスワードが開発構成でのみ表示されている場合でも、コードが存在し、一度に多くの構成変数を無害に見えるように変更することで再アクティブ化できることを意味します。管理者からパスワードを隠すことは一般的な慣行です。パスワードは、私が今まで見たWeb以外の一般公開されたソフトウェアでは記録されません。システム管理者とITサポートスタッフは、ユーザーが目の前でパスワードを入力しているときに、日常的に目をそらしています。
  • バグ報告が行われたアプリケーションの開発者。その役割がパスワードにアクセスすることはありません。エラートレースにパスワードを含めることは、たとえそれらのトレースから最も多くの使用をしている人にのみ表示されたとしても、良くありません。
  • 攻撃者がエラートレースのバックアップを盗んだり、誤った設定(誤ってdisplay_errors=onを設定したなど)によるバックトレースを確認したりすることができます。

資産としての間違ったパスワードの価値は、それが何であるかによって異なります。正しいパスワードのタイプミスである場合、間違ったパスワードは正しいパスワードと同じくらい価値があります。パスワードが別のサイトのパスワードである場合(おっと、実稼働サイトのパスワードをテスト環境のユーザーログインフォームに入力しました)、そのサイトの資格情報と同じくらい価値があります。間違ったパスワードを明らかにすると、高価値の資産を開示するリスクが高くなります。

開発者の応答は非常に不十分です。

はい、display_errors = onで運用サーバーを実行し、引数を付けてバックトレースを出力することはセキュリティ上のリスクがあります。だから絶対にやらないでください。

第1に、ログが正当に表示されるユーザーにのみ表示される場合でも、開発環境でも強力なセキュリティ上の懸念があります。

第二に、すべてが「セキュリティリスク」ですが、一部のリスクは他のリスクよりも深刻です。バックトレースは、それ自体が資産である可能性がある、または攻撃パスの1つのステップになる可能性がある機密情報を明らかにする可能性があります。これは、銀の大皿にパスワードを渡すほど悪くはありません。

何よりもまず、この応答はセキュリティについて非常に狭い見方を示しています。「私のソフトウェアを正しく使用すれば、直接的なリスクはありません」。それが真実であっても(そうではありません)、セキュリティは全体的な懸念事項です。大規模なシステムのすべてのコンポーネントが、そのコンポーネントの作成者が意図したとおりに正確に使用されるようにすることは困難です。したがって、コンポーネントは堅牢でなければなりません—これは「多層防御」とも呼ばれます。 「パスワードをログに記録しない」のようなルールは、「バックトレースを表示してはいけない人(誰に?.

パスワードが何で何がそうでないかを認識するのが難しい場合があります。パスワードを非表示にすると、パスワードが常に非表示になるという期待が生まれると主張できます。これは、パスワードが非表示でない場合は悪いことです。成功率は、ここで最善の努力をすることを正当化するのに十分以上だと思います。

例外の発生時に何らかの理由で資格情報を返送することはありません。渡されたものを確認するためにvar_dumpの出力のようなものを行うのは開発者の責任です。

もちろん、ユーザーに例外メッセージを表示しないことがベストプラクティスです。他の状況では、サイトをさらに悪用するために簡単に使用できますが、これは簡単すぎるため、そのような詳細を渡す理由が明確ではありません。バック。

MySQLのエラーははるかに優れています(user @ address、password yes/no)、有益ではありますが、それほど多くのデータ漏洩はありません(ただし、内部アドレスや私の認証メカニズムを人々に知られたくないと主張することはできます)。

PHPは、実際にはまったく手を握っていないこと、および(ドキュメントが不十分であるため)何か間違った場合にサメに放り投げられることでも知られているため、コースに並ぶようです。

10
StrangeWill

PDOがそれを行う方法は完全に間違っており、それに言い訳はありません。

エラーメッセージは、適切に構成されたシステムであっても、エラーログ、ユーザー向けのエラーメッセージなど、あらゆる種類の場所に行き着きます。メリット(不正なパスワードを特定すること)は、せいぜいわずかです。このようなエラーが発生した場合、原因は無効なSQL、制約違反、ネットワークの問題、または破損したDBサーバーなどです。パスワードが実際に間違っている場合でも、それを表示する理由はありません。 「データベース資格情報が無効です」または「データベースへのアクセスが拒否されました」というメッセージをスローするだけで十分です。パスワードが意図したものではないことが疑われる場合、これを具体的にデバッグする方法はたくさんあります。リスクがまったくない場合でも、エラーメッセージにパスワードを含める必要はありません。

PHPバグリポジトリを参照すると、この問題と同様の問題について多くの議論が見つかるはずです。簡潔にするために、この問題は死ぬまで議論され、開発者は、現在の動作に問題があることに同意していないようです。そのため、すぐに変更される可能性はほとんどありません。

つまり、自分で解決策を考え出す必要があります。機能する最後の解決策は、str_replaces一連のアスタリスク付きの実際のパスワード。または、PDOをスローしないように強制することもできますが、例外ベースのエラー処理の快適さが失われ、PDOのエラーメッセージをサニタイズする必要があります(PDOとPDOStatementsから自分で退屈にする必要があります)。

9
tdammers

Str_replace()を使用してパスワードを非表示にするだけです。

// Connect using PDO
try 
{   
    $this->dbh = new PDO('mysql:Host='.DB_Host.';dbname='.DB_NAME , DB_USER , DB_PASS); 
    $this->dbh->setAttribute(PDO::ATTR_ERRMODE , PDO::ERRMODE_EXCEPTION);           
}
catch(PDOException $e)
{
    echo str_replace(DB_PASS, ' *** LOOK @CONFIG FOR YOUR SECRET PASSWORD! *** ' , $e);
}
0
jones