2ch トリップ仕様

掲示板にトリップ機能を搭載したものの、利用者から"2chトリップ検索スレで探してもらったトリップが使えない"などの苦情が出てしまった。そんな管理者・サイト作成者のために、2chトリップと同じものを出力する方法をまとめてみました。

仕様概要

2ch掲示板システム(以降2ch)の投稿処理スクリプト(以降bbs.cgi)に実装されているトリップの仕様において、重要な事項を以下に挙げます。

  • POSIX準拠のCRYPT(3)に基づいています。Perl, PHP などではcrypt(key,salt)により容易に利用できます。ハッシュアルゴリズムはDESベースのものを用います。すなわちCRYPT(3)のSalt引数にて$により指定できる拡張暗号化アルゴリズム(MD5など)は利用しません。
  • 2ch は Shift_JIS ベースで構成されたサイトです。すなわち記事投稿(カキコ)フォームにて入力された文字列は基本的に Shift_JIS にて bbs.cgi に渡されます。必然的にトリップキーも Shift_JIS エンコードであることが前提となります。2chはトリップキーの入力に対し制限を課していません。
  • bbs.cgi はマルチバイト非対応Perl5にて記述されています。受け取ったトリップキーはマルチバイト処理を施さず、バイト(オクテット)単位で取り扱うようにします。
  • Salt は実装上の歴史的理由により、トリップキーの2文字目および3文字目から変換表により一意に決定し、ドット, スラッシュ, 数字, アルファベット大文字, アルファベット小文字の 64 種で構成される文字 2 文字で表し、CRYPT(3)に渡す必要があります。

以下、2ch実装の現状ではあるが仕様不備であると考えられる項目を挙げます。2ちゃんねる文字化け対策@レアトリップ配信所も参考にしてください。

  • bbs.cgi の文字エスケープ(HTMLのメタ文字を置換)は、トリップキーに対しても行われます。また、bbs.cgi の文字エスケープ規則は独特(あえて言うなら不完全)です。
  • bbs.cgi の語句置換処理(いわゆるNGワード)もまた、トリップキーに対して行われます。置換の対象語句はマルチバイトであるにもかかわらず、非マルチバイトにて置換が行われるため、一見置換対象でない文字列に対しても置換が行われることがあります。
  • bbs.cgi 稼働サーバOS(FreeBSD)のCRYPT(3)には、他OSと互換性がなく対策も困難である仕様が存在します。FreeBSDではキーバイト列に 0x80 が含まれている場合にそれをキー文字列の終端(0x00)と見なし、以降のバイト列は 0x00 であるかのごとく処理してしまいます。一部のShift_JIS全角文字がこの仕様に抵触します。

また、クライアント(ブラウザ)依存の問題として、クライアントが扱う文字コードは純粋な Shift_JIS ではないという点があります。これに関しては掲示板システム実装者が積極的に関知する必要はありません。

掲示板システムに2chトリップを実装するために

基本的に、以下の項目に従えば、2chトリップと互換であると見なされます。逆に、以下を逸脱している場合には、2chトリップと同じものを出力することは困難となります。

  • トリップキーは Shift_JIS エンコードにてCRYPT(3)に入力する必要があります。サイトが EUC, UTF-8 など、Shift_JIS以外で構成されている場合には、トリップキーを適宜文字コード変換処理により Shift_JIS に変換してください。
  • トリップキー中の空白文字などをトリップキー終端と見なしてはいけません。空白も含めて最短8バイトをトリップキーとして扱う必要があります。実際に入力されたトリップキーが8バイト未満の場合はその限りではありません。
  • トリップキーにはHTMLエスケープおよびSQLエスケープを施してはいけません。CRYPT(3)の出力は、入力されるトリップキーを"サニタイズ"していると考えてください。システム上エスケープを施す必要がある場合は、エスケープ処理より先にトリップキーの抽出分離を行ってください。
  • Salt は 2ch 規則に従って生成します。後述します。
  • 表示するトリップは、CRYPT(3)により得られた出力文字列(13文字)の末尾10文字を取り出して用いてください。出力の先頭2文字は入力のSaltと同じもの、すなわちトリップキーの一部であるため、外部に出力してはいけません。

2ch と同様の結果を得るためには、さらに以下の項目を実施することになります。いずれを施さなくても、利用者側でキーを一部改竄することにより対応可能なので、必須ではありません。

  • トリップキーに対しても、非マルチバイト処理にてエスケープ・NGワード置換を行います。
  • トリップキー中の 0x80 を認識し、それ以降の文字を切り落とすことにより、2chサーバ制限と同様の結果を得ることができます。

Perl(マルチバイト非対応)

以下のコードはbbs.cgiにて使われているものとほぼ同様のものです。

  1. if($FORM{'FROM'} =~ /([^\#]*)\#(.+)/){
  2. my $main_message = $1;
  3. my $handle_pass = $2;
  4. my $change_salt = substr($handle_pass, , 1) . "H";
  5. $change_salt =~ tr/\x3A-\x40\x5B-\x60\x00-\x2D\x7B-\xFF/A-Ga-f./; # 2003/11 追加
  6. $handle_pass = substr(crypt($handle_pass, $change_salt), -10);
  7. }

$FORM{FROM} はエスケープなどがすでに行われています。本質的にはエスケープを行う必要はありません。

Perl(use Encode)

(後日加筆予定)

PHP4

(後日加筆予定)

Salt生成規則

ここでは、トリップにてCRYPT(3)のために用意するSaltの生成規則について説明します。

Salt は、トリップキーの2文字目および3文字目それぞれから文字を取り出し、以下の規則を用いて決定します。

取り出した文字生成する文字全角文字の2バイト目備考
ピリオド【.】
スラッシュ【/】
数字【0-9】
そのまま-
アルファベット大文字【A-Z】
アルファベット小文字【a-z】
そのまま
【:】【A】-
【;】【B】-
【<】【C】-2chでは先だってエスケープ処理により消滅するため該当ナシ。
【=】【D】-
【>】【E】-2chでは先だってエスケープ処理により消滅するため該当ナシ。
【?】【F】-
【@】【G】
【[】【a】
【\】【b】
【]】【c】
【^】【d】
【_】【e】
【`】【f】
それ以外【.】0x7B-0x7E【{|}~】および 0x80-0xFC は、全角文字の2バイト目に含まれます。

以上の変換規則をキャラクタコード順に並べると以下の表のようになります。

0123456789ABCDEF
0x00................
0x10................
0x20.............../
0x300123456789ABCDEF
0x40GABCDEFGHIJKLMNO
0x50PQRSTUVWXYZabcde
0x60fabcdefghijklmno
0x70pqrstuvwxyz.....
0x80................
0x90................
0xA0................
0xB0................
0xC0................
0xD0................
0xE0................
0xF0................

歴史

昔はこうだった系の読み物です。うんちくネタにどうぞ。もちろん知らなくても掲示板システムにトリップを実装することはできます。

Salt の扱い

数年前、新鯖トリップと言われる仕様が突如出現しました。このとき2chではトリップ仕様変更が行われたワケではなく、単にサーバOSの更新が行われただけでした。

トリップ仕様が変更になったように見えたのは、実は、仕様に定められていない範囲外のSaltをCRYPT(3)に渡していたが故の、OS(ライブラリ)依存の仕様外動作によるものでした。2chにトリップが実装され始めた頃のサーバは libc5 ベースのSlackware, "新鯖トリップ"が出る鯖は glibc2 ベースの OS でした。

さらに FreeBSD ベースのサーバが導入された際、単に期待したトリップが出ないだけでなく、トリップそのものが何も出ない状態になってしまいました。FreeBSDライブラリのCRYPT(3)は、仕様外Saltをエラー扱いするようになったためです。そのため2ch側もbbs.cgiにおける対策が必要となってきたのです。対策されて以降、基本的にトリップ仕様は揺れ動いていません。

範囲外Saltにおける動作は、公開されているそれぞれのライブラリ(libc5, glibc2, FreeBSD)のソースコードを追跡することで裏付けを取ることができます。glibc2の場合、0xFF→0x00 が連続していて、0x7F→0x80 が不連続であるのがミソです。

以下は対策前のトリップ算出コードです。ひろゆき(2ch初代管理人)により公開されました。このままではSaltに仕様範囲外の文字を渡すことができるどころか、拡張暗号化指定すら紛れ込ませることが可能になるため、"MD5トリップ"を表示させることも可能になっていました。末尾に / 0 1 を表示させることができていたのです。もちろん現在ではMD5トリップの表示は対策により不可能になっています。

  1. if($FORM{'FROM'} =~ /([^\#]*)\#(.+)/){
  2. my $main_message = $1;
  3. my $handle_pass = $2;
  4. my $change_salt = substr($handle_pass, , 1) . "H";
  5. $handle_pass = substr(crypt($handle_pass, $change_salt), -10);
  6. }

新鯖(glibc2)によるSalt変換表を以下に示します。漢字など全角文字が含まれるトリップキーにおいて、Saltの互換が取れなくなってしまうことがわかるでしょう。

0123456789ABCDEF
0x00GHIJKLMNOPQRSTUV
0x10WXYZabcdefghijkl
0x20mnopqrstuvwxyz./
0x300123456789ABCDEF
0x40GABCDEFGHIJKLMNO
0x50PQRSTUVWXYZabcde
0x60fabcdefghijklmno
0x70pqrstuvwxyz./012
0x80GHIJKLMNOPQRSTUV
0x90WXYZabcdefghijkl
0xA0mnopqrstuvwxyz./
0xB00123456789ABCDEF
0xC0GHIJKLMNOPQRSTUV
0xD0WXYZabcdefghijkl
0xE0mnopqrstuvwxyz./
0xF00123456789ABCDEF

See also