【絶対必須】phpのセキュリティ対策!XSSとメールヘッダーインジェクションを防ごう

この記事からわかること
- phpによるセキュリティ対策方法
- よくある攻撃の種類と仕組み
- 実際に使用できるセキュリティ対策コード
index
[open]
\ アプリをリリースしました /
PHPでプログラムを作成する中で1番大事になってくるのがセキュリティです。
PHPではユーザーから入力された値を元にデータベースに格納したり、メールを送ったり、webサイトを変更したりとできることは多岐にわたりますよね。
その際に適切なセキュリティ対策をしておかないと大変なことになってしまいます。今回は主な攻撃とセキュリティ対策の実際のコードをまとめていきます。
クロスサイトスクリプティング(XSS)
クロスサイトスクリプティング(XSS:Cross Site Scripting)とはユーザから入力された値によって情報が盗まれたり、勝手にリダイレクトされたりと言った作り手が許可していない挙動を引き起こさせることです。
例えばこのようなコードは危険とされています。
$_GETはURLの末尾経由で情報を譲渡できます。以下のコードが記述してあるphpファイルのURLの末尾に「?test=<script> alert("JavaScriptを実行しています"); </script>」 と入力するとjavascriptが実行されポップアップが表示されてしまいます。
URL:【https://www.○○○.com?test=<script>alert("JavaScriptを実行しています");</script>】
//このURLを直接指定すると。。。
<?php echo $_GET['test'] ?>
//(⇧)このコードがGET['test']の値(⇩)に切り替わり実行されてしまう
<script>alert("JavaScriptを実行しています");</script>
これはユーザから入力された値を実際のコードとして認識してしまっているためにおこる挙動です。
これを防ぐためには適切なエスケープ処理が必要になってきます。
エスケープ処理とは入力された値をただの文字列として認識させたりコードの一部として認識しやすい「>」や「""」などを置換したり、削除したりすることを指します。
では実際のコードをみていきましょう。
クロスサイトスクリプティングの対策コード
XSS対策として有効なのはhtmlspecialchars関数です。
htmlspecialchars関数はHTMLファイルにおいて特殊な意味をもつ「>」や「""」などを文字列に変換する関数です。
htmlspecialchars関数の引数
htmlspecialchars(対象文字列[,int エスケープの種類(デフォルト値= ENT_COMPAT | ENT_HTML401)[,文字コード(UTF-8など)]])
※エスケープの種類はこれを使えば大丈夫です!
ENT_QUOTES:ダブルクォート/シングルクォート共に変換
ENT_HTML5:HTML5の記述として処理
実際に使用例をみてみましょう。
URL:【https://www.○○○.com?test=<script>alert("JavaScriptを実行しています");</script>】
<?php $data = htmlspecialchars($_GET['test'],ENT_QUOTES | ENT_HTML5); ?>
// エスケープ処理を施した値を受け渡すことでコードとして認識されず実行されない
<?php echo $data; ?>
//表示されるのはコードではなく文字列としての"<script>alert("JavaScriptを実行しています");</script>"
メールヘッダインジェクション
続いてはメールヘッダインジェクションについてです。
PHPではmb_send_mail関数を使うことで実際にメールを送信することができます。お問い合わせフォームや本人確認メールなどはPHPで作られています。
関連記事:【自作】PHPでお問い合わせフォームを作ろう!コードと仕組みを徹底解説!
mb_send_mail関数の引数
mb_send_mail(宛先,件名,内容,ヘッダ情報(ヘッダ名:値))
mb_send_mail関数
では引数にメールを送信するにあたって必要な情報を渡してあげます。
その中でも送信先のメールアドレスを引数として渡す際に正しいエスケープ処理をしないと勝手に違うメールアドレスに送られてしまうなどの被害が出てしまうことがあるのです。
メールを送信するmb_send_mail関数
は引数ヘッダ情報に値をセットするときヘッダ名:値
と記述します。複数記述するときはヘッダ名:値 \n ヘッダ名2:値2
のように「\n(改行コード)」で羅列していく方法になります。
そのため入力値に「\n」のエスケープ処理をしていないと自由にヘッダ情報を追加することができてしまうのです。
<?php
$to = email@email.com ;
//mb_send_mail(宛先,件名,内容,ヘッダ情報(ヘッダ名:値))
mb_send_mail($to,$_POST['title'],$_POST['body'],"From:{$_POST['from']}");
?>
// $_POST['from'] = "from@email.com \n Bcc:ame@email.com"
// ⇧このように入力するとFrom(送り主)を指定したかっただけなのに
// 【email@email.com】にしか送信しないはずのメールが
// 【ame@email.com】にも送信されてしまいます
メールヘッダインジェクションの対策コード
メールヘッダインジェクションを防ぐにはstr_replace関数を使います。
str_replace関数は対象文字列の中から検索文字列を探し出し、指定した文字に変換する関数です
この関数を使って入力値の中に含まれる改行コード("\r","\n")を置換してしまえば対策完了です。
str_replace(検索文字列,変換文字列,対象文字列);
実際の対策コード
<?php
$from = $_POST['from'];
$from = return str_replace(array("\r","\n"),'',$from);
// 悪意ある改行コードを空白に変換することで実行させない
?>
このほかにも入力されたメールアドレスを正規表現を駆使して使える文字を制限してしまうのも効果的です。
関連記事:【PHP】正規表現(PCRE関数)の使い方!チェックや置換するメソッドを解説!
SQLインジェクション
SQLとはデータベース(以下DB)を操作するプログラミング言語です。PHPの中でもSQLを使うことができるのでDBを操作することが可能です。
PHPでは入力された情報をDBに登録する新規会員登録システムやDBに登録された情報を元にログイン制御するログイン機能など、DBに値を挿入したり、取得したり、はたまた削除したりと何かと絡むことが多いです。
SQLインジェクションとはDB操作を実行するSQL文に入力値を絡めるときに悪意あるコードを埋め込まれてDBのデータを不正に操作されてしまう攻撃です。
注意すべきことは入力値をそのままSQL文に組み込まないということです。
SQLインジェクションの対策コード
SQLインジェクションの対策はDB操作にPDOを使っていると楽です。
PDO(PHP Data Objects)とは「データベース抽象型レイヤ」の1つです。データベース抽象型レイヤとはDB操作を1つのオブジェクトとして扱い、種類がたくさんあるDBの差異を吸収し共通したコードで操作できるようになります。
つまり異なるDBに変更されてもコードを変えなくても使えるようにするのがPDOの役割です。
SQL文に入力値を入れ込む場合はPDOの機能:プレイスホルダを使うと便利です。
プレイスホルダとは値を入れ込むところを一旦別の文字にしておき、後から挿入する場所のことを指します。
PDOではプレイスホルダが「?」と「:名称(例:name)」の2パターンの方法が用意されています。
このプレイスホルダを使うことで使用した入力値に対して自動でエスケープ処理を施してくれます。私たちが何も気にしなくて良くなるので便利ですね!
<?php
$sql = 'INSERT INTO login_table (name,sex,email,pass) VALUES (?,?,:email,:pass)';
// ?(プレイスホルダ)をこのように列挙する
$stmt= $dbh->prepare($sql);
// 値を入れ込むときに内部的にエスケープ処理をしてくれる
// bindValue(入れ込むプレイスホルダ,入れ込む値,データ型)
// ?の場合は何番目の?か指定
$stmt->bindValue(1,$name,PDO::PARAM_STR);
$stmt->bindValue(2,$sex,PDO::PARAM_STR);
$stmt->bindValue(:email,$email,PDO::PARAM_STR);
$stmt->bindValue(:pass,$pass,PDO::PARAM_STR);
?>
PDOについてはこちらに詳しくまとめてありますのでご覧ください!
おすすめ記事:【PHP】PDOとは?プリペアドステートメントの使い方とメソッドの種類
PHPのセキュリティ対策と良くある攻撃のまとめ
【クロスサイトスクリプティング】
- 攻撃方法:入力値やURLにphpやJavaScriptを埋め込まれる
- 対策方法:「"」などの特殊文字を文字列として認識させる
- コード :htmlspecialchars関数
【メールヘッダインジェクション】
- 攻撃方法:メールのヘッダ情報に「\n」などの改行文字を含ませ送信情報を変更する
- 対策方法:「\n」を強制排除、入力値がメールアドレスか振るいにかける
- コード :str_replace関数、正規表現
【SQLインジェクション】
- 攻撃方法:SQL文を改ざんさせる
- 対策方法:「\n」を強制排除、入力値がメールアドレスか振るいにかける
- コード :str_replace関数、正規表現
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。