【PHP】htmlspecialchars関数でエスケープ処理をしてください【XSSの防止】

どーも、服のサイズがMからLになったヨシダです。
やせよ…

みなさん!エスケープ処理してますか!(アントニオ猪木風に)
エスケープ処理とは、マークアップ言語やプログラミング言語、スクリプト言語等で文字列を扱う際に、その言語にとって特別な意味を持つ文字や記号を、別の文字列に置き換えることです。
これをしないと、クロスサイトスクリプティング(XSS)が行えちゃいますから、システムに色々問題が発生してしまいます。
まあ、実際にどのようなことが起こるかは見てみないとわかないですよね。
百聞は一見にしかずって言うし。

てことで、以下の環境で掲示板を作成してみました。

OS CentOS
Web Server Apache
言語 PHP
データベース MariaDB

 

できたのがこんな感じです…

 

 

「送信」を押したら、上に書き込まれて行きます。
例えば、下のように書き込んで

 

 

ここから「送信」をポチっとな。

 

 

いえええええええええええええええい!!!(サンシャイン池崎風に)
(しょぼいとか言わないで)

ちゃんとデータベース(MariaDB)にも書き込まれています。

 

 

特に問題ないんじゃねーの?と思うかもしれませんが、問題ありありなんですよ。
この掲示板は、まだそのエスケープ処理がされていません。

では、ここに「<script>alert(1)</script>」と書き込んでみましょう。

 

 

「送信」をポチっとな。

 

 

あべし!(北斗の拳風に)
スクリプトが発生してしまいましたね。
これがクロスサイトスクリプティング(XSS)です。
このサイトに訪れれば、誰でもこのアラートが発生してしまいます。
アラートじゃなくて、違うページに飛ばすスクリプトだったりもできますし、色々できちゃいますので、非常に危険です。

この「<script>alert(1)</script>」をスクリプトとしてではなく、文字列として出力するために、エスケープ処理を行います。
現状、以下のようにPHPで文字を出力しています。

 

 

これでは、データベースに保存した文字をそのまま出力しちゃってるのがわかります。
そりゃあ、XSSが発生してまいますよ。
ここで、登場するのが「htmlspecialchars」です。
PHPの関数のひとつです。

使い方は「htmlspecialchars(エスケープする文字列, エスケープの種類, 文字コード);」になります。

基本的に第二引数のエスケープの種類は「ENT_QUOTES」を指定します。
ENT_QUOTES を指定することで、下記にようにエスケープを行ってくれます。

  • 「”」(ダブルクォート)が「&quot;」に変換されます。
  • 「’」(シングルクォート)が「&#039;」または「&apos;」に変換されます。
  • 「<」が「&lt;」に変換されます。
  • 「>」が「&gt;」に変換されます。

「ENT_QUOTES」以外にも「ENT_COMPAT」や「ENT_NOQUOTES」等複数ありますが、「ENE_QUOTES」よりエスケープしてくれる文字が少ないので使用する機会はほぼないです。

コードを書く時に、毎回長い「htmlspecialchars(エスケープする文字列, エスケープの種類, 文字コード);」を記述すると見づらくなってしまうので、短い関数名にしてしまうのが一般的です。
具体的には以下のコードになります。
—-

function h($s) {
return htmlspecialchars($s, ENT_QUOTES, "UTF-8");
}

—-
というわけで、出力するところを下のように書き換えてみました。

 

 

これで試しにもう一度「<script>alert(2)</script>」を書き込んでみます。

 

 

まあ、この時点で「<script>alert(1)</script>」がちゃんと出力されてますが(笑)
「送信」をポチっとな。

 

 

O〜〜〜K〜〜〜!!!(狩野英孝風に)
ちゃんとアラートのスクリプトが発生せずに、文字として出力されていますね。

このエスケープ処理は非常に大切なのに、ちゃんと実装されていないページが多すぎます。
例えば、お問い合わせページの確認画面とかは多いですね。
入力フォームにスクリプトをいれて確認ページに移動してみると、発生しちゃったりね。

システムエンジニアさんは、この処理をお忘れなく!

今日の記事は色々すべってましたね。
実は、文章中にでてきた「<script>alert(1)</script>」←これ自体とかも、エスケープ処理がされてるから、今あなたがみてる画面にアラートが発生してないんですよ。
実際には「&lt;script&gt;alert(1)&lt;/script&gt;」←こんな風に記述してます。
ややこしいですね(笑)

ありがとうございました。

LINEで送る
Pocket

こんな記事も読まれています