安全なウェブサイトの作り方

情報処理推進機構が Web サイトの脆弱性対策についてまとめた資料を公開しています。


情報処理推進機構 安全なウェブサイトの作り方
http://www.ipa.go.jp/security/vuln/websecurity.html


・安全なウェブサイトの作り方
・安全なSQLの呼び出し方
についてそれぞれ PDF 資料があり、内容が充実していてよく整理されていると思います。

脆弱性対策は多様化しているので、個々人の開発者が全てを熟知して対策するのは難しそうです。堅牢なシステムを作るには、熟知した人によるチェック・テストが欠かせないですね。

Access の全クエリーの SQL から文字列検索

Access 2000 で、あるテーブルがどのクエリーで使われているかを調べようと思ったのですが、クエリーの数が非常に多く、デザインビューなどで1つ1つ開いて調べるのはやっかい、という場面に出くわしました。

そこで調べてみると、クエリーの SQL をテキストファイルに出力するサンプルを紹介してくれている方がいました。これを使えば、出力したテキストファイル内を検索すれば調べられます。


http://questionbox.jp.msn.com/qa708589.html


以下はプログラムそのままの引用になります。クエリーを読み取ってテキストファイルに出力し、それをメモ帳で開いています。

Private Sub Command_Click()

    Dim Dbs         As DAO.Database
    Dim Qdf         As DAO.QueryDef
    Dim FileName    As String
    Dim FNum        As Integer
    Dim stSQL       As String
    Dim ret         As Double

    'データベースセット
    Set Dbs = CurrentDb
    'Set Dbs = DAO.OpenDatabase("c:\test.mdb")

    'ファイルを開く
    FNum = FreeFile
    FileName = Mid(Dbs.Name, InStrRev(Dbs.Name, "\") + 1)
    FileName = Left(FileName, InStrRev(FileName, ".") - 1)
    FileName = "c:\" & FileName & "_Query.txt"
    Open FileName For Output Access Write As #FNum

    'クエリ分ループ
    For Each Qdf In Dbs.QueryDefs

        'クエリ名&SQLステートメント取得
        stSQL = "QueryName:" & Qdf.Name & vbCrLf & _
                "SQL:" & Qdf.SQL & vbCrLf & vbCrLf

        'ファイルに出力
        Print #FNum, stSQL

    Next

    Set Dbs = Nothing

    Close #FNum

    'ファイルを開く(notepad.exe)
    ret = Shell("notepad.exe " & FileName, vbNormalFocus)

End Sub

Windows→Linuxへ自動ファイル転送

kaijikaiji2009-11-11

ローカルのWindows端末でコーディングしたファイルをLinuxサーバ等に転送して動作確認するようなシステム開発の場合、毎回転送ソフトを使って手作業で転送するのは結構手間になります。何か良いツールはないものかと調べたところ、SSHでファイル転送してくれるWinSCPを使えば更新したファイルだけ自動転送できることがわかりました。

ミラーリングアップロードを開始させておくと、ローカルのファイルの追加・修正・削除を検知して即時にサーバへ反映してくれます。これはかなり使えそうです。ただし、ファイル数が500個以上になると検知が遅くなってくるようです。

設定方法は、下記サイトのミラーリングの項目に記載があります。

▼WinSCP3の使い方
http://osksn2.hep.sci.osaka-u.ac.jp/~naga/miscellaneous/winssh/winsshb1.html

Zend Framework のセッション有効期限

ログイン認証を行うWebアプリは適切にセッション有効期限を設定する必要がありますが、Zend Framework(1.9.2)の Zend_Auth を使うと、ログインしてから一定時間経過後にセッションが切断されるとのこと。
そうではなく、最後にアクセスした後一定時間放置したらセッションが切断されるようにしたかったのですが、そのような機能は用意されていないようです。
実現するシンプルで良さそうな方法が見つからなかったのですが、以下のようにすると出来ます。

$authSession = new Zend_Session_Namespace('Zend_Auth');
$authSession->setExpirationSeconds(600);

これを毎度のアクセスの度に実行するようにしておけば、アクセスの度に有効期限を更新できるというわけです。
正当な方法という感じはしないですが、とりあえずこれで・・・。

Zend Framework+MySQLの文字化け対策

PHP5 + Zend Framework 1.9.2 + MySQL5 で、DBからデータを取得したときに文字化けするのを防ぐ方法について。

以下のように「set names utf8」を先に発行しておけば文字化けは防げるが、汎用的な Zend_Db を使っている以上、やはり MySQL 特有のコマンドは使いたくないしSQLインジェクションを引き起こす可能性があります。(参考 SET NAMESは禁止:http://blog.ohgaki.net/set_namesa_mcb_asc

$db = Zend_Db::factory('Pdo_Mysql', array(
        'host'          => 'xxx.xxx.xxx.xxx',
        'username'      => 'xxx',
        'password'      => 'xxx',
        'dbname'        => 'xxx'
));

$db->query("set names utf8");

そこで調べてみると、factory() のパラメータに charset を指定できることが判明。以下のようにすると、文字化けを防ぐことができました。

$db = Zend_Db::factory('Pdo_Mysql', array(
        'host'          => 'xxx.xxx.xxx.xxx',
        'username'      => 'xxx',
        'password'      => 'xxx',
        'dbname'        => 'xxx',
        'charset'       => 'utf8'
));

これでよしよし・・・と思ったのですが、念のため Zend Frameworkソースコード(Zend/Db/Adapter/Pdo/Mysql.php)を見てみると、「set names xxx」を使っているじゃないですか! PDO の driver_options パラメータに「set names xxx」を渡していました。SQLインジェクションは大丈夫なのでしょうか・・・?
以下がソースコードの一部引用です。

protected function _connect()
{
    if ($this->_connection) {
        return;
    }

    if (!empty($this->_config['charset'])) {
        $initCommand = "SET NAMES '" . $this->_config['charset'] . "'";
        $this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND
    }

    parent::_connect();
}

ちょっと不安なので、Pdo_Mysql ではなく Mysqli を使うことに。これで文字化けせずにうまく動きました。

$db = Zend_Db::factory('Mysqli', array(
        'host'          => 'xxx.xxx.xxx.xxx',
        'username'      => 'xxx',
        'password'      => 'xxx',
        'dbname'        => 'xxx',
        'charset'       => 'utf8'
));

Mysqli の ソースコード(Zend/Db/Adapter/Mysqli.php)を見ると、mysqli_set_charset() で文字コードをセットしていました。これを使えば、SQLインジェクションは大丈夫なようです。

Socket通信でレスポンスが遅い

PHP プログラムで Web サーバと SSL 通信すると非常にレスポンスが遅くなるという
現象に出くわしたので、その対処方法を書いておきます(HTTP通信でも同じ現象になるかもしれません)。


fsockopen() で 443 ポートに接続し、データを送受信する以下のプログラムでは、レスポンスが遅くなります。

$send_data = '送信データ';

$fp = @fsockopen("ssl://192.168.0.xxx", 443, $errno, $errstr, 30);

$request = "";
$request .= "POST /xxx.php HTTP/1.1\r\n";
$request .= "Host: 192.168.0.xxx\r\n";
$request .= "Content-Type: text/plain\r\n";
$request .= "Content-Length: " . strlen($send_data) . "\r\n";
$request .= "\r\n";
$request .= $send_data;
$request .= "\r\n";

fputs($fp, $request);

while(!feof($fp)) {
	$response .= fgets($fp, 4096);
}
fclose($fp);

「HTTP/1.1」→「HTTP/1.0」にするとレスポンスは速いのですが、HTTP/1.1 では遅くなります。
調べてみると、HTTP/1.1 では持続接続機能が追加されたようで、接続が維持された状態になって終了されず遅くなっていたようです。
リクエストヘッダに「Connection: Close」を入れてやると、接続を維持せず終了するとのことです。


以下のように「Connection: Close」を入れると、レスポンスが速くなりました。

$send_data = '送信データ';

$fp = @fsockopen("ssl://192.168.0.xxx", 443, $errno, $errstr, 30);

$request = "";
$request .= "POST /xxx.php HTTP/1.1\r\n";
$request .= "Host: 192.168.0.xxx\r\n";
$request .= "Content-Type: text/plain\r\n";
$request .= "Content-Length: " . strlen($send_data) . "\r\n";
$request .= "Connection: Close\r\n";
$request .= "\r\n";
$request .= $send_data;
$request .= "\r\n";

fputs($fp, $request);

while(!feof($fp)) {
	$response .= fgets($fp, 4096);
}
fclose($fp);