ルール 1: 外部データや入力を決して信頼しない
Web アプリケーションのセキュリティについて最初に認識しなければならないことは、外部データを信頼すべきではないということです。外部データには、プログラマによって PHP コードに直接入力されないデータが含まれます。他のソースからのデータ (GET 変数、フォーム POST、データベース、構成ファイル、セッション変数、Cookie など) は、セキュリティを確保するための手順が講じられるまで信頼できません。
たとえば、次のデータ要素は PHP で設定されているため安全であると考えられます。
リスト 1. 安全で完璧なコード
$myUsername = 'tmyer';
$arrayUsers = array('tmyer', 'tom', 'tommy'); 'こんにちは' . $myUsername);
?> ただし、次のデータ要素にはすべて欠陥があります。
リスト 2. 安全でない欠陥のあるコード
$myUsername = $_POST['username'] //汚染されています!
$arrayUsers = array($myUsername, 'tom', 'tommy' ); /tainted!
define("GREETING", 'hello there' . $myUsername); //tainted!
最初の変数 $myUsername が間違っているのはなぜですか?これはフォーム POST から直接取得されるためです。ユーザーはこの入力フィールドに任意の文字列を入力できます。これには、ファイルを駆除したり、以前にアップロードしたファイルを実行したりする悪意のあるコマンドも含まれます。 「A ~ Z の文字のみを受け入れるクライアント側 (Javascript) フォーム検証スクリプトを使用すれば、この危険を回避できないのですか?」と疑問に思われるかもしれません。はい、これは常に有益なステップですが、後で説明するように、誰でもあらゆるフォームを自分のマシンにダウンロードし、変更して、必要なものを再送信できます。
解決策は簡単です。サニタイズコードは $_POST['username'] で実行する必要があります。これを行わないと、(配列や定数などで) $myUsername を使用するたびに、これらのオブジェクトが汚染される危険があります。
ユーザー入力をサニタイズする簡単な方法は、正規表現を使用して処理することです。この例では、文字のみが受け入れられることが想定されています。文字列を特定の文字数に制限したり、すべての文字を小文字にすることを要求したりすることも良いアイデアかもしれません。
リスト 3. ユーザー入力を安全にする
$myUsername = cleanInput($_POST['username']) //clean!
$arrayUsers = array($myUsername, 'tom', ' tommy' ); //クリーン!
function cleanInput($input){
$clean = preg_replace ("/[^a-z]/", "", $clean);
$clean = substr($clean,0,12);
?>
ルール 2: PHP を無効にするセキュリティの実装を困難にする設定
ユーザー入力を信頼できないことがわかったので、マシン上での PHP の構成方法も信頼すべきではないことも理解する必要があります。たとえば、register_globals が無効になっていることを確認してください。 register_globals が有効な場合、$variable を使用して GET または POST 文字列を同じ名前に置き換えるなどの不注意な行為が可能になります。この設定を無効にすると、PHP は正しい名前空間の正しい変数を参照するように強制します。フォーム POST から変数を使用するには、$_POST['variable'] を引用符で囲む必要があります。こうすることで、この特定の変数を Cookie、セッション、または GET 変数と間違えることがなくなります。
ルール 3: 理解できない場合、保護することはできません
一部の開発者は、奇妙な構文を使用したり、ステートメントを非常に厳密に編成して、短くても曖昧なコードを形成します。このアプローチは効率的かもしれませんが、コードが何をしているのかを理解していないと、コードを保護する方法を決定できません。
たとえば、次の 2 つのコードのうちどれが好きですか?
リスト 4. コードを保護しやすくする
//難読化されたコード
$input = (isset($_POST['username']) ? $_POST['username']:'');
//難読化されていないコード
$input = '';
if (isset($_POST['username'])){
$input = $_POST['username']
}else{
$input = ' ' ;
}
?>
2 番目のよりクリーンなコード スニペットでは、$input に欠陥があり、安全に処理する前にクリーンアップする必要があることが簡単にわかります。
ルール 4: 「多層防御」が新しい魔法です
このチュートリアルでは、フォームを処理する PHP コードで必要な措置を講じながら、オンライン フォームを保護する方法を例を使用して説明します。同様に、PHP 正規表現を使用して GET 変数が完全に数値であることを確認する場合でも、SQL クエリでエスケープされたユーザー入力が使用されることを確認する手順を実行できます。
多層防御は良いアイデアであるだけでなく、深刻な問題に巻き込まれないようにします。
基本的なルールについて説明したので、最初の脅威である SQL インジェクション攻撃を見てみましょう。
SQL インジェクション攻撃の防止
SQL インジェクション攻撃では、ユーザーはフォームまたは GET クエリ文字列を操作することでデータベース クエリに情報を追加します。たとえば、単純なログイン データベースがあるとします。このデータベースの各レコードには、ユーザー名フィールドとパスワード フィールドがあります。ユーザーがログインできるようにするログイン フォームを作成します。
リスト 5. 単純なログイン フォーム