Webアプリケーションと セキュリティ
Webアプリケーションが高機能になると、使いやすさが増します。しかし、Webアプリケーションが高度になって行く一方で、危険性が増すのも事実です。ここでは、Webアプリケーションを作る上で気をつけるべき、セキュリティ上の問題について考えます。
Webアプリケーションのセキュリティホール
テンプレートエンジンやWebアプリケーションサーバを使うと、高度な機能を持つWebアプリケーションを比較的手軽に作れるようになります。高度な機能を持つWebアプリケーションは便利で使いやすいものです。しかし、機能が高度になっていくにつれ、いろいろな危険性が紛れ込む余地が増えるのも事実です。
開発者が、自分の作ったプログラムに危険性を意図的に埋め込むことはまず考えられないでしょう。そういう意味では、ソフトウエアに潜む危険性は開発者が意図しない形で現れることが多いのかも知れません。このように、開発者が意図しない操作が許されてしまうような欠陥のことをセキュリティホールと呼びます。また、本来見えるべきでない情報が第三者に見えてしまうような不具合も同様にセキュリティホールと呼ばれます。
プログラムの欠陥は、動作原理に大きな関わりを持っています。Webアプリケーションに見られるセキュリティホールは、Webアプリケーションの動作原理に大きく関わっています。Webアプリケーションでは文字列操作を頻繁に行います。そのため、セキュリティホールの多くは文字列に関わった形で現れます。
セキュリティホールの例
では、実際にWebアプリケーションに見られる典型的なセキュリティホールを見てみましょう。
まず、簡単な問い合わせフォームを作ってみます。「xsstest.py」というファイル名でcgi-binフォルダに保存します。本書で作ったWebアプリケーションサーバ、テンプレートエンジンなどを使いますので、モジュールファイルを同じ階層に置く必要があります。なお、セキュリティホールの実験のために作るWebアプリケーションですので、お問い合わせフォームとしては機能しません。
xsstest.py
:::python
#!/usr/bin/env python
# coding: utf-8
from simpleappserver import expose, test
from httphandler import Response
from simpletemplate import SimpleTemplate
htmlbody=u"""<html><body>
<h2>お問い合わせフォーム</h2>
<form>
名前 :<br/>
<input type="text" name="name" value="${name}"/> <br/>
本文 :<br/>
<textarea name="body" cols="40" rows="10">${body}</textarea> <br/>
<input type="submit" name="submit" value="送信" />
</form>
</body></html>"""
@expose
def index(_request, name='', body='', submit=''):
res=Response()
t=SimpleTemplate(htmlbody)
body=t.render({'name':name, 'body':body})
res.set_body(body)
return res
if __name__=='__main__':
test()
スクリプトファイルを直接起動するとWebアプリケーションが動き出します。Webブラウザでhttp://127.0.0.1:8000/にアクセスすると、フォームが表示されるはずです。
このWebアプリケーションでは、クエリで名前(name)や本文(body)を受け取ってフォームの中に埋め込むようになっています。本書で作ったWebアプリケーションでは、クエリが関数の引数として渡されます。送信するクエリはGETでもPOSTでも同じように扱われます。
では、以下のようなURLをWebブラウザに入力したら何が起こるでしょうか。GETリクエストで、クエリに文字列を渡しています。まるで、フォームの一部が書き換えられてしまったように見えるはずです。
http://127.0.0.1:8000/?name=%22/%3E-abcde-
図01 Webブラウザ上に任意の文字列が表示されてしまう
ソースコードに埋め込まれたテンプレート文字列を見返すと、value="${name}"というようになっています。つまり、クエリの「name」の文字列がvalue="~"の内部に埋め込まれるわけです。GETのクエリ「name=%22/%3E-abcde-」の部分は、URLエンコードという 手法で文字列が変換されています。もともとは「/>-abcde-」という文字列でした。この文字列が埋め込まれることで、HTML的に見るとinputエレメントが閉じられて、その後の文字列がエレメントの外にあることになるわけです。
エレメントのvalueアトリビュートに文字列を埋め込むこの機能は、もともとフォームの入力に誤りがあったときなどに、前回入力された値をフォームに埋め込むために作った機能です。しかし、このように本来の目的を超えた、想定外の利用方法が存在するわけです。このフォームが企業のWebサイトに設置されていて、GETのパラメータとして、悪意のある内容を持った文字列が指定されたらどうなるでしょうか。この機能が、ある種の攻撃に利用されてしまうかもしれません。
このようなセキュリティホールはクロスサイトスクリプティング(XSS)と呼ばれています。HTMLの文字列としての性質を利用したセキュリティホールと言えます。