大規模データを扱う場合はデータベース管理システム (DBMS) を使うわけです が、(来訪カウンタなど)小規模データで DBMS を使うまでもない場合、通常 の (DBMSで管理されていない)ファイルを使ってデータ処理をする場合があり ます。その場合、注意しないといけないことがあります。
例えば、あるページでAさんが入力データの送信を開始したとします。書き込
んで更新ボタンを押すと、データファイルはオープンされ、データは処理され
たのち保存され、ファイルは閉じられるわけですが、ほぼ同時、厳密にいうと
Aさんがファイルをオープンしてから閉じるまでの間にBさんが書
き込もうとしたらどうなるかを考えてみます。
Bさんが書き込もうとした瞬間にはAさんの書き込みは完了していません
から元のデータがBさんの書き込み処理データとして読み込まれます。
そして、Bさんがデータを書きかえて、そのファイルを閉じようとした時、
既にAさんの書き込みはファイルに保存されているわけですが、B
さんはそんなことは分かりませんので、通常の処理として閉じようとして、
ファイルを上書きします。つまり、運が悪いとAさんが書きか
えた内容は無くなってしまうというわけです。これは本来あってはなら
ないことです。
データが無くなりはしないまでも、2つのプロセスがてんでんばらばら (非同期…後述) にデータ処理をおこなうとすると、本来順序のあるデー タが、ばらばらの並びになって書き込まれる、という可能性もおおいにありま す。
もちろん DBMS を使えば上記のようなことにはならない(整合性を管理してく れる)わけですが、高々数バイトのデータの読み書きでいちいちDBMS を使う ほどでも無い場合、という前提です。このような状況にならないために、ファイルをロックする、という ことをするのが一般的です。つまり、Aさんが書き込みを開始したら、Aさん がファイルを閉じるまでそのデータファイルはBさんをはじめ他の人(プ ロセス)がオープンできないようにするわけです。そうすると、Bさん は、Aさんがファイルを閉じて他の人に操作を許可(解放)するまで待って、 その後Bさんの書き込みを開始すればよい、ということです。このような処理 は、上のような好きな時に処理するのではなく、タイミングをはかって処理を おこなうという意味で同期処理と呼ぶことがあります。
逆に、上にあったような任意のタイミングでの処理は非同期処理と呼 びます。
あるいは、ロックをかけにいって失敗したら待たずに別の処理をしてから、少 し時間をおいてロックをかけにいく、というやり方もあります。その場合は 「少し時間をおいて」という処理を自分で工夫して書くことで、効率のよいス クリプトになります。
ちなみに来訪カウンタや掲示板のような単純な制御の場合にはさほど問題には ならないですが、複数の処理(プロセス)が絡み合って処理を進めていく場合、 単純なファイルロックをおこなうと、複数のプロセスがお互いにずっと待ちの モードにはいってしまって処理が止まってしまうことがあります。これを デッドロック と呼び、これも絶対に避ける必要があるのですが、ここで は詳細は略します。以下のコードはサンプルです。ちなみに多くのプログラミング言語ではロック 機能があらかじめ提供されており、php, perl 等では flock 関数を 用いることで実現できます。以下は flock する場合の例(PHP スク リプト)です。
ちなみに flock は、ネットワークドライブの場合にはうまく動かない場合があ ることも記憶にとめておいてください。その場合は、自前でロックルーチンを つくります(ディレクトリをつくって、それをロックファイルとみなして処理 する)。
Webページに入力データをそのまま表示している部分があると、当然タグを含 めて全ての文字が表示できるわけですが、悪い人がページ内に <script> タグを使ってスクリプトを埋め込み、それを見たユー ザとサーバ自身の両方に被害を及ぼすクロスサイトスクリプティング (厳密にはスクリプト混入…後述)という不正の手口に利用さ れてしまう可能性があります。これは、実は結構入りくんだ攻撃手法であり;
クロスサイトスクリプティング脆弱性の本質的な原因は、標的Webサイト に外部から任意のスクリプトを混入できてしまう、ということで、この ため、スクリプト混入問題とクロスサイトスクリプティング脆 弱性を混同している人も多いのです。しかし、クロスサイトスクリプティ ング脆弱性はスクリプト混入問題の中の問題の1つにすぎません。とはいえス クリプト混入問題はクロスサイトスクリプティング脆弱性以外にもさまざまな セキュリティ上の問題を引き起こすのでいずれにせよ対策が必要なのはかわり ません。
現実的かつ危険な例として、以前 JavaScript で習ったスクリプトで クッ キーを設定 した後、 この怪しい(つもり) のページをアクセスしてみてください。
ここではオウム返しの(つまり、脆弱性のある) test2.php を悪用して、 ma.echan.xyz が puffin.hannan-u.ac.jp のクッキーを盗めていることがわか るでしょう。...すいません、外部公開用にサーバの設定をかえたので、動かなくなっています。 以下は動いたテイで読みすすめてください。(2020.11.15)
動くようになりました。(2021.11.17)ちなみに上の この怪しい(つも り)の crack.cgi の中身は以下のようなものです(本当は URL 部分はそ れぞれ一行)。
Click me (echo-back) !
☆重要☆ 本来、puffin.hannan-u がうめこんだクッ キーは、そのクライアントPCと埋め込み元の puffin.hannan-u 以外は読 むことが出来ない はずなのに、 http://ma.echan.xyz/_C_/cookies.txt に保存されて いる、ということは、ma.echan.xyz = 第三者 が盗み見できている、 ということになります(わかりますか?)但し、ブラウザの設定によっては document.cookie を返さないようにするこ とも出来るようです(その場合は盗まれないので、セキュリティレベルは高い、 ということになります)。
Webアプリケーションで、入力データをHTMLページへ埋め込む処理はつきもの です。しかし、もし入力データに悪意あるスクリプトが含まれていた場合、 WebアプリケーションはHTMLページへ悪意あるスクリプトを埋め込んでしまう ことになります。そこでサニタイジング (sanitizing) =スクリ プトの無効化ということが必要になります。
サニタイジングとは入力データから危険な文字を検出し、置換・ 除去することで、入力データを無害化する処理です。クロスサイトスク リプティング対策での入力データの無害化とは主にスクリプトを無効化 することになります。サニタイジングを施してスクリプトとして機能し なくなった入力データは、そのままHTMLページへ埋め込むことができますので、 適切なサニタイジングにより、ユーザのブラウザへスクリプトがそのまま送ら れることを阻止できるわけです。具体的に一番よくやられている対処法は php ならば以下の関数を出力時に挟んで、タグ等を無効化する(別の 字におきかえる)、ということです。以下は php での例です。
function sanitise($buf) { $buf = str_replace("&","&",$buf); $buf = str_replace('"','"',$buf); $buf = str_replace("'","'",$buf); $buf = str_replace("<","<",$buf); $buf = str_replace(">",">",$buf); return $buf; }正規表現 についての詳細は略して、結論からいえばHTMLタグ の属性値部 分に入力データを埋め込む場合 に上の5つの文字を置き換え て サニタイジングするということです。
ちなみに「&...;」は、ブラウザ上では「&><」(ここではいわゆる全 角記号を使ってます)等の、タグ等の構成要素としての記号として表示されま すが、元の HTML テキストでは特殊記号ではない方法で(エスケープ して)記述するための記法です。
上では 5つの文字を置換していますが、実際には元のスクリプトのほうで入力 データをダブルクオートでくくった場合シングルクオートの置換は不要で、ま たシングルクオートでくくった場合ダブルクオートの置換は不要だったりしま す。とはいうものの余分に置換しても問題はないので、ダブルクオートとシン グルクオートの両方を置換することにしておいたほうが無難かもしれません。
ちなみにサニタイジングは、Web アプリケーションが HTMLを生成する時の タイミング で行ったほうが無難です。どうしてかというと、詳細は略し ますが、データを埋め込むHTML中の文脈に合わせて適切な、場合によってはタ グの無効化以外のサニタイジング手法を選択する必要があるからです。また、 同じデータに誤って2回以上サニタイジングしてデータの意味が変わってし まう というミスも防げる、等の利点もあります。
その他、タグ属性はクオートすべき、とか、イベントハンドラも無効化すべき、 等と細かいことはいろいろあるのですが、ここでは詳細は略します。とりあえ ず、まずはタグを無効化しないといけない、ということを最低限覚えておいて ください。
$sql = "DELETE FROM USERS WHERE NAME = '$id'";上記のようにSQLを組み立てる式があった場合、SQLインジェクションとして、
$id = "' OR 'a'='a"; # 実際には入力欄に「' OR 'a'='a」を入力とすると、組み立てられたSQLは以下のようになって、
DELETE FROM USERS WHERE NAME = '' OR 'a'='a'この文での条件(WHERE節)は 「NAME = '' OR 'a'='a'」ですが、これはつまり 「『 NAME が空』または 『'a' と'a'は等しい』 」 となり、後者は 常に正しいので、常にこの条件はなりたつこととなり、結果として 全て のユーザを削除 することになります。以下のスクリプトで 体験できます。 初期化 削除(脆弱性あり) このような操作を防ぐためには、まずなにはなくとも 「'」のエスケー プ(記号の置き換え/無効化) が必要になります。
次に、数字チェックが必要な場合の例ですが、IDとして数値型を使用している 場合のSQLは、
$sql = "DELETE FROM USERS WHERE ID = $id";などと「'」が入らないわけですが、
$id = '0 or TRUE'; # 実際には入力欄に「0 or TRUE」を入力とすれば、組み立てられたSQLは、
DELETE FROM USERS WHERE ID = 0 or TRUEとなり、上と同様にすべてのユーザを削除できることになります。今回は削除 の条件設定でしたが、これが select (検索・表示)で使えれば、そのデータベー ス内の全データが閲覧できる(情報を抜き取れる)わけです。
今回の場合は数値型を想定した変数に文字列を入力するわけですから、perlと かphpなど、 型の無い(とまでは言わなくても、ゆるい) 言語でな いと発生しにくいと思いますが、現実にこういうことはありがちだと思います。 このように、数値項目に対するSQLインジェクション対策としては、 数字 判定 が必要になります。本来、セキュリティ以前の問題として、数字判 定はもちろん加えて、 桁数や最小・最大のチェック もやっておくべきでしょう。
ちなみに、ここに書かれた内容を悪用して「不正アクセス行為の禁止等に関す る法律」にふれる行為を行なった場合は処罰の対象になるので、実験するとし ても、必ず自分の管理するコンピュータでのみ行なってください。 何 か不都合がおこっても責任はとりかねますので悪しからず。