00メニュー > 01はじめてのMySQL > 02MySQLの基礎知識 > 03MySQLを使いこなす > 04MySQL+PHPの基礎 > 05MySQL+PHPの実践 > 06Appendix

20インターネットに公開するときの対策(備忘録)→ > 01p > 02p > 03p > 04p > 05p > END

05MySQL+PHPの実践

PHPを使ってMySQLへアクセスできるようになったら、今度は簡単なWebアプリケションを作ってMySQLと連携してみましよう。ここでは、PHPとMySQLと連携してみましよう。ここでは、PHPとMySQLを使って掲示板の作成、そしてインターンネットに公開するときの注意点など勉強します。
☆CHAPTER19⇒PHPとMySQLで簡単掲示板を作る
★CHAPTER20⇒インターネットに公開するときの対策
☆CHAPTER21⇒ちょつと実用掲示板の作成

★CHAPTER20⇒インターネットに公開するときの対策(p432)★

  これまでLocalhostで行なってきた知識を使って「さっそくWebアプリケーシヨンをレンタルサーバに置いて公開」インターネットには、不特定多数の人が行き交います。あらゆる危険性に対して備えておかなければ、大事なデータベースが危険にさらされます。インターネット上にWebアプリケーションを安全に運用するのに必要な、最小限の知識について触れます。

(1)《公開されるフォルダに重要な情報を置かない p451》

(1-1)<PHPファイルの仕組み>

Webページを公開するときは、Webサーバー上の公開されるフォルダにファイルを置きます。 公開されたファイルは、インターネットに接続できる人ならば、もちろん誰でもダウンロードが可能です。 では、データベースを操作するスクリプトも、接続した人にダウンロードされてしまうのでしょうか?もし、誰でも自由にダウンロードができて、その内容を見ることができるのなら、サーバー名やユーザー名、そしてパスワードまでも、世間に公開していることになります。 実は、公開されるでPHPが動作する設定になっていれば、「.php」の拡張子を持つファイルにアクセスするとスクリプトが実行されます。PHPスクリプトファイルにアクセスしたクライアントに返されるのは、スクリプトが実行した結果だけです。 さらには、サーバー上にあるファイルの内容を他人に見せたくない場合は、一般的には属性を変更してアクセスできないように制限をかけます。さらに注意が必要です。 ※パスワード等の重要な情報が書き込まれたファイルを、公開するフォルダに置くだけは大変危険なことだと思った方が無難です。 では、重要な情報をスクリプトで扱うときは、どうしたら良いでしょうか。

(1-2)<別ファイルのスクリプトを読み込む方法>

Webサーバーとなるコンピュータは、必ず、「公開されないフォルダ」が設定できます。 重要な情報を含むファイルは、必ず、「その場所が推測されにくい、非公開のフォルダ」におきます。

●require_once

PHPスクリプトには、別のPHPスクリプトファイルを読み込む機能がいくつか用意されています。ここでは例として、require_onceコマンドを使うことにします。 この関数でファイルを読み込んだ場合、「ファイルを一度だけ」読み込み、「読み込めない場合は処理を中止」します。

●書式⇒require_once

require_once(読み込みファイル名) ※まず、「サーバー名」「ユーザー名」「パスワード」「データベース名」を記述したファイルを作ります。このファイルは公開されないフォルダに保存します。 次のファイルを作成し、ファイル名を「db_info.php」として、公開されないフォルダ「data」に保存するものとします。

■db_info.php

<?php
$SERV="localhost";
$USER="root";
$PASS="1234";
$DBNM="db1";
?>
※前項のデータベースに接続するスクリプト「kantan_select.php」を改良して、この基本情報を保存したファイル「db_info.php」を読み込むようにします。
変更するには、データベースに接続する次の部分です。

●変更前

$s=mysql_connect("localhost","root","1234") or die("失敗しました");
print "接続OK!<BR>";
mysql_select_db("db1");

●変更後


require_once("data/db_info.php");
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
print "接続OK!<BR>";
mysql_select_db($DBNM);
※「require_once("data/db_info.php")」 では、dataフォルダにある「db_info.php」を読み込んでいきます。
※変更後の全体のスクリプトは次の通りです。


■kantan_select2.php
<?php
require_once("data/db_info.php");
$s=mysql_connect($SERV,$USER,$PASS) or die("失敗しました");
print "接続OK!<BR>";
mysql_select_db($DBNM);


$re=mysql_query("SELECT * FROM tbk ORDER BY bang");
while($kekka=mysql_fetch_array($re)){
print $kekka[0];
print " : ";
print $kekka[1];
print " : ";
print $kekka[2];
print "<BR>";
}
mysql_close($s);
print "<BR><A HREF='kantan.html'>トップメニューに戻ります</A>";
?>
※単純に、「require_once("data/db_info.php");」の読み込んだファイルの内容が挿入されると考えてよいでしょう。同様の変更を他の「kantan_insert.php」「kantan_delete.php」「kantan_search.php」にも加えれば、もし、スクリプトの内容を見られたとしても、パスワード等まで見られてしまうことはなくなります。

(2)《クエリに不正なデータを入れられないようにする p454》

(2-1)<SQLインジェクションとは>

パスワード等、重要な情報が見られなければPHP+MySQLは安心なのか、というと、決してそんなことはありません。むしろ、もっと怖くてやっかいなのがSQLインジェクションです。 インジェクション(injection)は、「注射する」とかお金を「つぎ込む」といった意味に使われます。つまり、「Webアプリケーションの作者が予想しなかったデータ」を混ぜる(注入)ことで、不正な処理を行なわせる攻撃方法です。

●SQLインジェクションを体験する

ここでちょっと考えてみてください。「kantan.htnl」の削除番号を入力するテキストボックスに、次のように入力して「送信」ボタンをクリックしたらどうなるでしょうか?
1 or 1=1
※最初の「1」で、1番目のレコードが削除されそうです。でも、その次の「or 1 = 1」とというのは、何ものなのでしょうか?
※これを上のSQL文に入れてみると、次のようになります。
DELETE FROM tbk WHERE bang=1 or 1=1
※これはつまり、1番目のレコードが削除されるだけでなく、テーブル「tbk」のすべてのレコードが削除されてしまうことになります。
※このように簡単に、「Webアプリケーション作者が意図しない、危険なクエリ」を発行することができてしまうのです。
※世の中には、もっともっと巧妙な「SQLインジェクション」を使って、さまざまな攻撃を仕掛けてくる人がいます。例えば、スクリプトの中身や変数が全部見えなくても、変数や処理の流れを推測して危険なSQL文の破片を注入してくるのです。
それではWebアプリケーションを公開するときに、いったいどのような対策をとればよいのでしょうか?

●数値以外を入力させないようにする

例えば上の例なら、「数値以外のデータが送信されたら、DELETEを実行させない」という仕組みを作ればよいでしょう。送信されるデータは、削除するレコード番号なので、もし、アルファベットが含まれている場合は削除せず、警告メッセージを送るようにする。
チェックする方法は、いろいろありますが、ここでは「正規表現」と「preg_match」関数を使った方法を解説します。

(3)《正規表現 p000》

(3-1)<正規表現とは>

正規表現とは、「このような文字パターン(秩序やルール)になっているかどうか」という条件を記述する方法です。例えば、[0-9]という表現は、「0から9までの数字が含まれている」ということを意味します。

(3-2)<正規表現の例>

ここでは、以下に代表的な例を紹介します。

●[]の中の文字がどこかに含まれている

正規表現⇒内容 [7]→どこかに7が含まれている [0-9]→どこかに数値が含まれている [a-z]→どこかに小文字のアルファベットが含まれている [A-Z]→どこかに大文字のアルファベットが含まれている [A-Za-z]→どこかに大文字かまたは小文字のアルファベットが含まれている [A-Z][0-9]→どこかに、最初が「大文字のアルファベット」で次が「数字」という連続した文字パターンが含まれている

●[]の中で指定した文字以外が含まれている

[^0-9]→0から9の文字以外が含まれている(数字以外が含まれている) [^A]→A以外が含まれている [^A-Z]→大文字のアルファベット以外が含まれている [^0-9a-zA-Z]→数字とアルファベット以外が含まれている

●^の次の文字で始まっている

^h→hで始まっている

●$の前の文字で終わっている

E$→Eで終わっている

●{}の前の文字が{}内の回数だけ連続している

7{3}→どこかに7が3個以上連続して含まれる

(3-3)<preg match関数>

正規表現を使ってあいまい検索を行なう関数に、preg_matchがあります。 「あいまい検索」とは、「この文字を探しなさい」というような厳密な指定でなく、「だいたいこんな感じの文字を探しなさい」というような、対象範囲を広めに取った検索です。 preg_match関数は、次のように記述します。

●書式⇒preg_match関数

preg_match(正規表現,調査する文字列)
※「preg_match」関数では、非常にポピュラーなスクリプト言語であるPerlと互換性のある正規表現を使って検索を行ないます。
この場合、正規表現の記述を一般に「/」(スラッシュ)を囲みます。例えば、「どこかに大文字かまたは小文字のアルファベットを含む」という正規表現は、「A-Za-z」です。
次は、「AからZ、そしてaからz、つまりアルファベットが含まれる」という正規表現です。
/[A-Za-z]/
次は「1234」を、「/[A-Za-z]/」という正規表現でチェックするものです。「1234」はアルファベットを含まないため、「含みません」を表示します。
■fukumu.php
<?php
if(preg_match("/[A-Za-z]/","1234")){
print "含みます";
}else{
print "含みません";
}

(3-4)<正規表現を使って不正入力をチェックする>

もう1つ、正規表現の例を紹介します。「xxx-xxxx」の形式の郵便番号が入力されていることをチェックしてみよう。
「0~9が3つで始まる」→[-]→「0~9が4つで終わる」という文字の並びが含まれているか?という表現は、次のようになります。
「0~9が3つ」で→[0-9]{3}
「始まる」→^
「0~9が4つ」で→[0-9]{4}
「終わる」→($)
次は、変数「$m」の内容「107-0052」に対して、上のチェックを行う例です。
<?php
$m="107-0052";
if(preg_match("/^[0-9]{3}-[0-9]{4}$/",$m)){
print "とりあえずOKです";
}else{
print "誤りがあります";
}
?>
※この場合、正しいので「とりあえずOKです」と表示されます。
もちろん、実際にインターネットで公開するには、これでは不十分です。厳密に調べるためには、いろいろな正規表現を加えていく必要があります。

●DELETEコマンドを含むクエリを実行しないように改良します。

では、とりあえず前項で紹介した「mysql_query("DELETE FROM tbk WHERE bang=$b1_d");」
の部分で、数値以外の入力があった場合は警告を表示し、DELETE命令を実行しないように書き換えてみることにしましょう。
「mysql_query("DELETE FROM tbk WHERE bang=$b1_d");」の部分を、$b1_dの内容に数値以外が含まれる場合は次を書き出すことで警告を表示し、DELETE命令が実行されないよう書き換えましょう。
※数値以外が含まれる場合に書き出すコマンドは、次のようになります。
print "<FONT COLOR='red'>数値以外入力しないで!!</FONT><BR>";
以下は改良したkantan_delete.phpです。
■kantan_delete2.php
if(preg_match("/[^0-9]/",$b1_d)){
print "<FONT COLOR='red'>数字以外は入力しないで!!</FONT><BR>";
}else{
mysql_query("DELETE FROM tbk WHERE bang=$b1_d");
}

※変数「$b1_d」の値に、もしアルファベットなどが入力(0~9以外が入力)されると、「数字以外は…」のメッセージが表示され、DELETE命令を含むクエリが実行されることはなくなります。「数字以外は・・・」の「<FONT COLOR='red'>~</FONT>」が設定された文字列は赤色になります。
※昨今のSQLインジェクションにはさまざまな手口があり、そのすべてを解説することはできません。
でも、ひとまずはこれだけでも、余計なSQL文の混入は防げるというレベルの仕組みになります。

(4)《magic_quotes_qpc p000》

(4-1)<エスケープ処理されない例>

それでは次に、前項で登場した「okuri.html」のテキストボックスで、「"」を入力してから「送信」ボタンをクリックしてください。何が表示されましたか?「\」が付いて(\")表示されましたか?もしそれなら問題ありません。 もし、そのまま「"」と表示されていたら、これは何かの対策が必要です。

(4-2)<magic_quotes_gpcとは>

ちゃんとmagic_quotes_qpcがONになっている場合には、「okuri.html」を開いて「"」を入力してから「送信」ボタンをクリックすると、ちゃんと「\」が付いて表示されます。 これは、「magic_quotes_qpc=ON」が設定されていますと「"」や「'」「\」やNULLがあった場合はエスケープ処理され、自動的に「\」が付くためです。「\」が付けば、送信する文字列に作者が意図しないSQL文を与えることが困難になります。 ※SQLインジェクションを回避するために、PHPの初期設定では、「magic_quotes_gpc」の設定がONになっています。

(4-3)<magic_quotes_gpcの設定と確認>

「magic_quotes_gpc」の設定は、「php.ini」にあります。設定する「pho.ini」は「c\xampp\apach\bin」にある。別な場所にある「php.ini」を設定しないように注意。 なお、「magic_quotes_gpc=off」になっていれば「On」に直して下さい

(4-4)<文字コードが「シフトJIS」の場合>

ただし、文字コードが「シフトJIS」に設定してある場合、問題が起こる場合があります。 例えば、「okuri.php」で、「代表」「暴力」「パソコン」などの文字列を送信した場合、「uke.php」によって、文字化けが出ることがあります。 ※シフトJISでは、「表」「暴」「ソ」のそれぞれの文字コードは「95 5c」「96 5c」「83 5c」になっています。そして、「\」の文字コードも「5c」なのです。そのため、たとえば「暴」のコードの一部である「5c」が「\」と間違えられてしまい、「5c」コードがエスケープ処理されてしまったわけです。 ※なお、「シフトJIS」以外の文字コードを利用すれば、基本的にはこの問題は発生しません。

(4-4)<文字コードが「シフトJIS」の場合>

ただし、文字コードが「シフトJIS」に設定してある場合、問題が起こる場合があります。 例えば、「okuri.php」で、「代表」「暴力」「パソコン」などの文字列を送信した場合、「uke.php」によって、文字化けが出ることがあります。 ※シフトJISでは、「表」「暴」「ソ」のそれぞれの文字コードは「95 5c」「96 5c」「83 5c」になっています。そして、「\」の文字コードも「5c」なのです。そのため、たとえば「暴」のコードの一部である「5c」が「\」と間違えられてしまい、「5c」コードがエスケープ処理されてしまったわけです。 ※なお、「シフトJIS」以外の文字コードを利用すれば、基本的にはこの問題は発生しません。

(5)《意図しないタグを実行させない p000》

(5-1)<タグ送信時の問題>

グの取り扱いも、Webアプリケーション作成時の重要なポイントです。それでは、前項の「okuri.html」「uke.php」で実験してみましょう。この2つのファイルは「okuri.html」のテキストボックスに文字を入力して「送信」ボタンをクリックすると、「uke.php」が単純に、これをprintで書き出すという仕組みです。では、ローカルにある「okuri.html」を表示します。テキストボックスに「<BODY bgcolor=black>」と入力して、「送信」ボタンをクリックして見てください。
<BODY bgcolor=black>
結果は、いきなりウインドウの中が真っ黒になってしまいます。
※「okuri.html」では、単純にテキストボックスに入力された文字を「uke.php」に送るだけ、そして「uke.php」は受け取った文字列をprintで書き出すだけです。

(5-2)<脆弱性への攻撃>

上記のように、Webアプリケーションの入力をそのまま画面に書き出すプログラムは危険です。こうしたトラブルを防ぐためにも、入力されたスクリプトを排除するWebアプリケーションを作る必要があります。

(5-3)<入力されたタブを取り除く>

入力された文字を、そのままWebアプリケーションに書き出す仕組みは危険です。 とりあえず、書き出す文字に含まれるタグを無効にする仕組みを設定しておきましょう。 このような場合には、タグなどの特殊文字を別の文字列に変換する「htmlspecialchars」関数を使います。

●書式⇒htmlspecialchars関数

htmlspecialchars(文字列)
※htmlspecialchars関数は、タグなどの特殊文字列を次のように変換します。

●htmlspecialchars関数による変換

変換対象文字⇒変換後
「<」⇒「&1t;」
「>」⇒「&gt;」
「&」⇒「&amp;」
「"」⇒「&quot;」
「'」⇒「&#039」
※悪意ある危険な入力でよく使われるのは、「<」「>」「&」「"」「'」などの記号です。

●htmlspecialchars関数は、これらの文字列を、その機能が実行できない文字列に変換します。

例えば、「uke.php」に、次のようにhtmlspecialcharsを使ってみましょう。
■uke_anzen.php
<?php
print htmlspecialchars($_POST["a"]);
?>
※単純に、受け取った値が代入される変数、「$_POST["a"]」に対してhtmlspecialcharsによる処理を加えただけです。
こうすることにより、送信された情報は、タグとしての機能でなく、文字列として画面に表示されます。

<まとめ>

●インターネットにWebアプリケーションを公開するときに注意すべき点
●パスワード等重要な情報を含むファイルの扱い方
●SQLインジェクションへの対策の例
●タグを混入させる攻撃への対策の例
※セキュリティ対策は、決して怠ることがあってはいけません。それには、自分の犯したミスが、自分だけの問題ではなく、不特定多数の人たちに迷惑を掛けてしまう可能性があります。常に、セキュリティ対策を意識することが重要です。

<チェック>

□SQLインジェクションとは何であるか理解している
□require_once関数を使って、別のファイルのスクリプトを読み込むことができる
□タグを無効にする方法を理解している
□preg_match関数と正規表現を使ったチェックの方法がわかる

<練習問題>

問題1
JavaScriptの命令は、次のタグの範囲中に記述します。 ■JavaScriputをHTMLに記述するタグ <SCRIPUT>~</SCRIPUT> またJavaScriputでは、alert("メッセージ")の命令で「メッセージ」を表示するダイアログボックスが表示されます。これらを利用して、「kantan.html」を次のように動作させるには、どのような内容を送信すればよいか考えて下さい。
JacaScriptが実行されるクライアントの環境で、一般ユーザーが「kantan.html」にアクセスすると、メッセージのダイアログボックスが表示される。

《解答1》

次のように、メッセージを入力用のテキストボックスに入力し、「メッセージ送信」ボタンをクリックします。
<SCRIPT>alert("メッセージ")</SCRIPUT>

【実行結果】

未処理