Webセキュリティ基礎知識

PHPやJavaScriptでウェブサービスを作成するときに、セキュリティに関する知識がないと脆弱なウェブサービスを作りがちです。
Webセキュリティに関する知識を身につけて、脆弱性対策を行いましょう。

また、脆弱性の対策以前に、プログラムをしっかりと書くようにしましょう。
バグを極力減らすことや、バリデーションをしっかりと行うことがセキュリティの観点からしても最も大切なことです。

クロスサイトスクリプティング攻撃

クロスサイトスクリプティング攻撃は、HTMLフォームに悪意のあるJavaScriptを挿入することにより成立します。
JavaScriptを利用して複数のサイトを横断させるなどすることで攻撃が成立します。
<form action='' method="post">
    名前を入力してください<input type="text" name="name" />
    <input type="submit" value="送信">
</form>
このようなフォームからPOSTされた値を
<?php
if(isset($_POST['name'])){
    echo $_POST['name'].'さん';
}
?>
PHPで受け取り出力するプログラムがあった。
通常であれば、名前のフォームに「山田」などの文字列が入力されるはずなので
PHPでの出力結果は「山田さん」のようになるはずです。
ところが、名前フォームに
<script>alert('XSS成功');</script>
などと入力すると、PHPでの出力結果が
<script>alert('XSS成功');</script>さん
となってしまい、JavaScriptが動作してしまいます。
このJavaScriptに悪質なコードが含まれていた場合、サイトの利用者が被害にあう可能性があります。
また、他の脆弱性の踏み台にされることもしばしばあります。

対策

PHP標準関数であるhtmlspecialcharsを使うことで、HTMLとして解釈される文字列をエスケープすることができます。

<?php
if(isset($_POST['name'])){
    echo htmlspecialchars($_POST['name']) . 'さん';
}
?>

上記の出力結果は

&lt;script&gt;alert('XSS成功');&lt;/script&gt;さん
このようになります。

クロスサイトリクエストフォージェリ攻撃

クロスサイトリクエストフォージェリは、別のサイトに用意した罠のリンクを踏ませることで
ユーザーが意図しないインターネットショッピングサイトでの購入や、
掲示板に意図しない発言が自分のPCから書き込まれたりする攻撃です。
<body onload="document.attackform.submit();">
<form name="attackform" method="post" action="http://example.com/bbs/register.cgi">
  <input type="hidden" name="title" value="攻撃者が指定した題名">
  <input type="hidden" name="article" value="攻撃者が指定した本文">
  <input type="submit" value="送信">
</form>
</body>

(上記ソースコードはWikipediaより引用)

上記のようなページをユーザーが閲覧した瞬間にhttp://example.com/bbs/register.cgiに文章が送信されてしまいます。

対策

<form action="" method="post">
  <input type="text" name="title">
  <input type="text" name="article">
  <input type="hidden" name="token" value="ワンタイムトークン">
</form>

このように隠しフォームで、毎回変わる暗号(ワンタイムトークン)を保持し、セッションにも同一の暗号を保存しておくことで、 双方が一致しているかを確認することで対策することができます。 暗号は予測不能な文字列とし、隠しフォームに予め入力する値はハッシュ値などにしておくとよいでしょう。

セッションハイジャック攻撃

セッションハイジャックはログイン済の状態を悪意ある人が乗っ取る攻撃です。
ログイン済みの第3者のセッションIDを盗み出すことで、乗っ取る方法の他に
こちらが指定したセッションIDを使ってログインさせることで、乗っ取る「セッション固定攻撃」というものもあります。

URLから流出

PHPでは、Cookieが利用できない場合、URLでセッション管理をする設定があります。
php.iniで利用するか設定することができます。
利用すると、URLの末尾にセッションIDが表示されます。

この時、サイト内からリンクをたどって他のサイトに移動すると
リファラからセッションIDが流出することがあります。

ノート

リファラはどこから来たかを知るために使います。主にアクセス解析や広告などに役立ちます。直前に見ていたURLが含まれます。

URLでのセッション管理は脆弱なので使わないようにしましょう。

XSSによる流出

セッションをCookieで管理している場合、
Cookieの中にセッションIDが保存されています。

CookieにはJavaScriptからもアクセス可能なため
XSSの脆弱性がある場合、悪意ある人にCookie内のセッションIDが盗まれる場合があります。

console.log(document.cookie);
対策としてはXSSと同様になります。

セッション固定攻撃による流出

ログイン前からセッションIDが割り当てられ、ログイン後も同じセッションIDが使われるサイトの場合
セッションIDを外から指定されて、固定されてしまうという脆弱性があります。

例:
test.php?PHPSESSID=aaaaaaaaaaaaaaa
のようにしてアクセスするとセッションIDが「aaaaaaaaaaaaaaa」になります。
ログイン後も同じセッションIDが割り当てられる仕様の場合、
セッションID「aaaaaaaaaaaaaaa」を使えばセッションハイジャックすることができます。

悪意ある人が上記のようなURLを利用させることで、特定のセッションIDでログインさせることで
乗っ取ることが可能になります。

セッションハイジャックを見破るには

通常の使用ではブラウザの言語やユーザーエージェントが途中で変わることはありません。
このような情報が途中で変わった場合、再度パスワードを入力させるなどするとよいでしょう。

SQLインジェクション攻撃

SQLインジェクションは、プログラムの設計者が意図しないSQL文を攻撃者が挿入することで、データベース内のデータを改竄したり盗み出したりする手法です。

<?php
$pdoObject = new PDO('mysql:dbname=testbase;host=localhost;port=8889', 'testuser', 'pass');
$pdoStatementObject = $pdoObject->query("SELECT * FROM user WHERE id = '". $_POST['user'] . "' AND pass = '". $_POST['pass'] . "'");

もし、$_POST[‘pass’] に 「’ OR 1 = 1」を入れた場合、実行されるSQL文は

SELECT * FROM user WHERE id = '' AND pass = '' OR 1 = 1
となり、全てのユーザーのデータを取得することができてしまいます。

この例以外にもセミコロンで区切ることで別のSQL文を連結させて挿入してしまうことも考えられます。

対策

PDOのプリペアドステートメントを使用することで、防ぐことができます。
詳細はPDOの項目を参照してください。
このドキュメントは Sphinx 1.2.1 で生成しました。