PEAK XOOPS - News in englishin japanese

Archive | RSS |
  
Poster : GIJOE on 2008-12-28 18:02:01 (8690 reads)

in englishin japanese
先日、gusagiさんより、bulletinHDについてのバグレポートとして、以下のURLを転送してもらいました。
http://ryus.co.jp/modules/d3blog/details.php?bid=107
先に結論から書くと、このエントリはMySQLの基本的なcase sensitiveルールを誤解していることによる、間違ったレポートです。
Quote:


この現象は、 Windows環境で作成したDBのデータをUNIX環境に持って行った場合に限定されます。

この時点でバグでも何でもありません。まずはこっちを読んでください。
http://dev.mysql.com/doc/refman/4.1/ja/name-case-sensitivity.html
Quote:

ただ、WARPなどの環境でデータを作成してから、UNIX環境にデータを移行して運用なんてケースも考えられるので、その場合は上記パッチを適用して頂いた方が良いと思われます。

そういう「仕様外」のことをやりたければ、lower_case_table_names=1 を使うべきでしょうし、もしなんらかの理由でソースコードを改変するしかない場合でも、Database::prefix()の方にかければ一箇所で済みます。SQL生成部すべてにstrtolower()をかける、という方法はメンテナンス性という観点からも筋が悪すぎます。

# 個人的には、Case sensitiveな環境がターゲットなのに、Case insensitive環境で開発しているっていうのがあり得ない…


ただ、このレポートのおかげで私も一つ勘違いしていたことに気付きました。
それは、caseしか違わないdirnameで、2つのモジュールが同時には動かせない、ということです。

当たり前ですが、case sensivie環境で動かすのなら、XOOPSにおけるdirnameも原則的にcase sensitiveです。例えば、XUGJのQandAフォーラムは、あくまで"QandA"であり"qanda"ではありません。(中身はd3forum)

http://www.xugj.org/modules/QandA/
上のリンクは生きてますが、
http://www.xugj.org/modules/qanda/
下のリンクは死んでます。

「つまり、D3モジュールでありさえすれば、picoがインストールされている環境でも、PICOというdirnameで別のモジュールとしてインストールできるだろう」

ここに思い込みがありました。

実際にはcase sensitiveな環境でもインストールできません。
なぜならSQLとして以下のクエリで判断されるからです。

SELECT (snip) WHERE dirname='PICO'

この 'PICO' はcase insensitiveに比較され、'pico'と一致します。

つまり、インストール済だよ、というメッセージで拒否されます。当たり前ですが、インストーラだけを無理矢理通過させても意味がありません。やはり同様のクエリによって、モジュールの分岐処理がなされるからです。

では、どうすれば良いのか。答えは簡単です。

ALTER TABLE (prefix)_modules MODIFY `dirname` varchar(25) binary NOT NULL default '';

としてあげれば良いのです。dirnameカラムにbinary属性を加えることによって、case sensitiveになりました。

これを実際に試してみると、picoとPICOが普通に共存できました。
まあ、そんな需要もほとんどないとは思いますが、ちょっとしたTipsくらいに覚えておくと、今後役に立つことがあるかもしれません。

なおこの場合、言語定数オーバーライド機能の一部が、picoとPICOでは独立して働きません。
それは、

$constpref = '_MI_' . strtoupper( $mydirname ) ;

というコードによるものです。

考えてみたら、定数名が大文字である必然性などどこにもなく、strtoupper() を$dirnameにかけることは、バグ以外の何物でもないでしょう。

今後のD3モジュールでは、$constprefへのstrtoupper()を外していきます。(各種言語ファイルに含まれてしまっているのがかなり面倒だったりしますが…)

0 comments

Poster : GIJOE on 2008-12-14 06:04:31 (11113 reads)

in englishin japanese
日本では年末に大掃除を行う習慣があります。
家中のガラス拭きをやった勢いで、altsysのmyblocksadmin機能について大掃除してみました。(半分嘘

実際、myblocksadminは私が積極的にメンテしているコードの中では最悪クラスの汚さで、機能的にも、WYSIWYG対応もspawのみ、新コアについてもXOOPS2.2のみ、と半端でした。

どうやら本家はXOOPS2.2を切り捨てることを完全に決断したようで、2.3という番号を冠しながら、中身は2.0.18の改良版のようなので、XOOPS2.2対応はやめました。いろいろ問題のあるspawもやめてます。

その代わり、というわけではないのですが、ImpressCMSに正式に対応しました。これで、D3モジュール群がImpressCMSでストレスなく使えると思います。正直、本家版についてまで、動作確認している暇はないのですが、XOOPS_VERSIONを見て、2.3なら、ImpressCMSと同じ扱いにしています。もしブロックポジションなどの仕様が同じであれば、XOOPS2.3でもすんなり動くかもしれません。

もちろん、WYSIWYGはcommon/fckeditor(fckxoops)に対応しています。これが入っていなければ警告が出るという親切設計!

XCL2.1コアの機能で、ブロック編集画面で表示対象グループが選べる、というのも、絶対にあった方が利便性が高そうなので、ついでに実装してます。ただ、これをまともにやると、group_permissionテーブルのgperm_idが異常に増大しそうなので、表示対象グループに変更がなければ同テーブルはいじらない、なんてあたりにも一応手間をかけました。

まるまる書き直した関係で、バグもいろいろありそうですが、ベータ版等と分けて管理する余裕もないので、一発勝負で0.70としてリリースしてます。

もし不具合があったらコメント等の方法で教えてください。


Poster : GIJOE on 2008-11-29 04:45:23 (15900 reads)

in englishin japanese
xoops.org (Mamba) がこんなニュースを出しました。
Security : Protector Security Fix for XOOPS 2.0.x and 2.2.x users

先に結論から言うと、無意味なレポートなので、無視して構いません。
XOOPS_TRUST_PATH内のファイルにアクセスされたらLFIだ、なんてトンデモなレポートですから

この世の中には、DocumentRootの外に置く部分と中に置く部分が別れているアプリケーションはごまんとあります。
むしろそういうアプリケーションの方が正しい設計であり、全部をDocumentRoot内に置く古いXOOPSの構造こそある意味おかしいと言えます。

もし、前者のようなアプリケーションについて、DocumentRoot外に置かれるべきコードをDocumentRoot内に置いて、そこに直接アクセスされたとしたら、そりゃあゴロゴロと「脆弱性」が出てくるように見えるでしょう。
少なくとも、PathDisclosureくらいはいくらでもあります。

でも、誰もそんな馬鹿げたレポートはしません。
なぜなら、DocumentRootの内か外か、というのは非常に重要な違いであると言うことを誰もが知っているからです。

XOOPS_TRUST_PATH はDocumentRootの外に置く
これは大原則です。

こんなニュースを出すという時点で、xoops.org は誰もセキュリティの基本を知らないことを露呈してしまっています。
(ニュースだけならサイト管理者であるMamba氏が無知なだけでしょうけど、ご丁寧にもphppp氏がメールで問い合わせまでしてきてます)

翻って、ImpressCMSを見てみると、彼らはちゃんとXOOPS_TRUST_PATHの意味を理解していることが判ります。例えば、mainfile.php 内のパスワード部分を、XOOPS_TRUST_PATH内に別ファイルとして保存しています。
(本当に必要かどうかはともかく)

つまり、xoops.orgからリリースされるXOOPSという名前のCMSより、ImpressCMSの方がお勧めだと言えるでしょう。


Poster : GIJOE on 2008-11-12 04:08:39 (13066 reads)

in englishin japanese
serialize()/unserialize()
var_export()/eval()

A)安全性

この2つのペアを一見して判るのが、後者でeval()を使う怖さです。当たり前ですが、var_export()の出力であることが保証されているテキストでなければ、アンシリアライズしてはいけません。

もっとも、unserialize()についても、ちょっと古いPHPであれば、バッファオーバー脆弱性があったわけで、シリアライズテキストがリクエスト依存、という状況はいずれにせよあり得ないでしょう。

B)速度

結果から書いてしまうと、serialize()/unserialize() の方がだいぶ速いようです。
こんな感じのベンチプログラムで検証してみました。


#!/usr/local/bin/(php-cli binaries)
<?php

function getmicrotime()
{
        list($usec, $sec) = explode(" ",microtime());
        return ((float)$sec + (float)$usec);
}

function var_import( $data ) {
        eval( '$ret='.$data.';' ) ;
        return $ret ;
}

$data = ( big array ) ;

$time_start = getmicrotime();

for( $i = 0 ; $i < $_SERVER['argv'][1] ; $i ++ ) {
        $serialized_data = serialize( $data ) ;
        $restored_data = unserialize( $serialized_data ) ;
        $serialized_data = var_export( $data , true ) ;
        $restored_data = var_import( $serialized_data ) ;
}

$time_end = getmicrotime() ;
echo $time_end - $time_start , "sec. \n" ;
?>

あくまでCLI版での検証ですが、赤は青のだいたい3倍くらいかかってます。PHPバージョン依存も確認してみましたが、PHP4.4.xでも5.2.xでも、同じようなパターンです。

ただ、eval()だけが遅いのかと思いきや、var_export()単独でも、serialize()の3倍かかります。

もちろん、この検証で重要なのは絶対値です。具体的な数字は書けませんが、シリアライズ/アンシリアライズなんてもともと小さな処理です。そこが3倍かかったくらいで、全体の処理にはほとんど影響ないはずです。(もちろん、大量に処理するケースでは避けた方が無難かも知れません)

C)使いやすさ

var_export()の圧勝です。
エンコーディング変換によるトラブルがなくなるだけでなく、シリアライズ形式でデータをいじることも、serialize()によるものより、はるかに楽です。

D)結論

失われてもさほど問題にならないデータや、大量のデータなら serialize()
重要性の高いデータで、さほど量が大きくないなら var_export()

という形で使い分けるのが良い気がします。
unserialize()で復元できなかった時の痛さと言ったら…

E)余談

ここでいきなりXOOPSの話題になって恐縮ですが、拙作picoでは、追加フィールド機能やフォーム機能で、serialize()/unserialize()を使っていました。しかし、この結論から、今後は、var_export()/eval()に変更していきます。

0 comments

Poster : GIJOE on 2008-11-11 18:28:10 (11031 reads)

in englishin japanese
PHPで配列やオブジェクトをシリアライズする際、一般に利用されているのはserialize()です。

しかし、serialize()されたテキスト形式が、結構やっかいです。
具体的には日本語などのマルチバイト処理と極めて相性が悪いのです。

もし、serialize()された状態で、テキストエンコーディングをEUC-JPからUTF-8に変更したりすると、もうunserialize()は効きません。フォーマットがバイト長に依存しているからです。

これだけなら、プログラミングレベルでカバーも出来るのですが、もっと厄介なのが、DBの自動エンコーディング変換とからむケースです。

たとえばXOOPSでは、セッションをDBに保存しています。そのセッションに日本語テキストをserialize()された状態で入れてしまうと、DBの自動エンコーディング変換で、テキストが元と別物になってしまうことがあります。MySQL4.1以上だと、内部的には常にUTF-8でデータを保持しています。EUC-JPのテキストに対しては、常にUTF-8への変換行われるので、EUC-JPとして取り出したとしても、実際には、

EUC-JP -> UTF-8 -> EUC-JP

という変換がかかっているのと同じです。そして、その際にどこかでバイト長がずれれば、unserialize()が効かなくなり、セッションが失われるわけです。

ここでクローズアップされるのが、PHPビルトイン関数だけで可能な、もう一つのシリアライズ方法です。

var_export()であれば、


array(
  'index' => 'value' ,
)

のようなテキストにシリアライズするので、eval() によってアンシリアライズ可能です。

そして、このテキストであれば、バイト長問題は発生しません。シリアライズしたテキストをエンコーディング変換しても、変換された状態でアンシリアライズ可能です。

…と、ここで時間切れなので、そのメリット・デメリット論は次回に。

0 comments

« 1 2 (3) 4 5 6 ... 55 »
Login
Username or e-mail:

Password:

Remember Me

Lost Password?

Register now!