Twitterの検索文をどこまで長くできるか軽く実験

Twitterには検索機能がありますが、ツイートの文字数と違って、検索に使える文字数にはこれと言って制限らしい制限は見当たりません。
そこで、検索にどれだけ長い文字列が使えるのか、検索文の長さを変えて確かめてみました。
まずは、「tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp アーモンド」(「tgws.fromc.jp」が33個の後に「アーモンド」1つ)の検索結果です。最後に違うキーワードが入っているのは、「××番目以降の単語を無視」という現象があるかどうかを確かめるためです*1

見ての通り、かなりつらそうな感じですが、ちゃんと検索できていますね。34単語、467文字はとりあえず大丈夫のようです。ちなみに、「tgws.fromc.jp アーモンド」の検索結果と内容は全く同じです。
それでは、「tgws.fromc.jp」を1つ追加した「tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp tgws.fromc.jp アーモンド」を検索した結果です。

Twitterが完全に音を上げました。
調べたのはここまでなので詳しいことはわかりませんが、この辺りがTwitter検索の限界のようです。複雑な検索条件を指定する場合には気をつけたいところですね。

2023/08/09追記

サービス名がXになった今、改めて検証してみました。

半角英数500文字

「test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test2 test2 test2 test2 test2 test3」
成功すれば、「test」「test2」「test3」を含む投稿が取得されます。

半角英数500文字での検索結果。正常に表示されている。

成功しました。

半角英数501文字

「test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test2 test2 test2 test2 test2 test2 test3」
成功条件同じく。

半角英数501文字での検索結果。無関係なツイートが表示されている。

無関係なツイートが現れました。失敗です。

全角文字(日本語)を含む500文字

「test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test テスト test2 test2 test2 test2 test2 test2 test3」
成功すれば、「test」「テスト」「test2」「test3」を含む投稿が取得されます。

全角文字(日本語)を含む500文字での検索結果。正常に表示されている。

成功しました。どうやらマルチバイト文字も1文字換算のようです。

結論

  • 500文字までOK
  • 501文字からアウト
  • 文字数でのカウントであり、バイト数などではない

2023/08/12追記

ORでハッシュタグを繋ぎまくったら400字いかないうちに値を上げました。
込み入った検索条件だと変動があるようです。

*1:例えばGoogleでは32語までに制限されている。

(unset)NULLへのキャスト

PHPには不思議な構文がある。NULLにキャストする(unset)という構文だ。
次のようにして使う。

$var = (unset)$somevalue;

こうすることで$varにはNULLが代入される。
わからない。次のように記述するのと何が違うのか。

$var = NULL;

マニュアルには変数をunsetするような旨が書いてあったが、実際にはそんなことはなく、値の評価結果がただNULLになるだけだ。
ある値をNULLとして代入したい場合には意味があるかもしれないいが、「NULLとしての値」はそもそもNULLしか存在しないわけで、「ある値」なんか持ち出さなくともNULLをそのまま代入しても全く同じ結果が得られるのだ。
また、(unset)は言語構造であるがゆえに、「値」や「可変関数」のように扱うことができず、ポリモーフィズム的に値をNULLにするような使い方もできない。
使い道はあるのだろうか。

$somevalue = 94404;
$var = 97998;

var_dump($somevalue);
var_dump($var);

$var = (unset)$somevalue;

var_dump($somevalue);
var_dump($var);

/* 結果
int(94404)
int(97998)
int(94404)
NULL
*/

Firefox4雑感

全体的にGoogle Chromeっぽくなった。

  1. タイトルバー・ツールバー周りがGoogle Chromeの劣化っぽい感じになった。使いやすい使いにくい以前に心理的に受け付けなかった。
  2. 劣化Google Chromeっぽいデザインはツールバーの右クリックメニューでメニューバーを選ぶことで簡単に直せる。旧来のデザインが好きな人は是非。
  3. 上記に限らずメニューバー、ツールバー、タブバー周りはそれなりにカスタマイズできる。
  4. ステータスバーはなくなった。ステータスバーに出てくるアイコンはアドオンバーに移動された。リンク先アドレスの表示はGoogle Chrome的。
  5. 複数回戻る・進むメニューはGoogle Chromeと同じく各ボタン長押しで出るようになった。右クリックでも出る。専用のボタンはなくなった。
  6. 更新ボタンと中止ボタンは隣り合っていると合体する。別々に表示したいときには間に区切りを入れる。
  7. スタイルの規定値が一部変更された模様。スタイルシート未指定時、リンクされている画像につく枠がなくなった。
  8. Firefox4に未対応のアドオンも強制的にインストールすれば動くことがある。
  9. SQLite Optimizerは未対応。今のままでも動く気がするけど、データベースはすぐ肥大化するわけじゃないので、対応まで待とうと思う。
  10. No Referrerは未対応だが完全に動作する。Google検索からはてなダイアリーに入るとハイライトだらけでひどいので個人的には必須アドオン。配布元が無くなった模様。
  11. ちょくちょく応答なしになる。旧バージョンと比べて頻度が増えた?

他、気になる点があれば追加していきます。

SQLiteManagerのデフォルトをsqlite3にする

SQLiteManagerという、ブラウザ上でSQLiteデータベースを操作できる便利なツール*1があります。
データベースを新規作成するとき、sqlite3が導入されていればSQLiteのバージョンとして2と3が選べます。
しかし、sqlite3がインストールされているか否かに関わらず、デフォルトはsqlite2のほうです。
sqlite3が入っている環境であれば、特に事情がない限り、わざわざ2を選ぶことはないと思います。
ところが、user_defined.inc.phpを見てみても、デフォルトのバージョンを切り替えるオプションはありません。
それもそのはず、デフォルトのSQLiteのバージョンはadd_database.phpの80行目*2にハードコーディングされているのです。

if(!isset($_POST['dbVersion'])) $forceDbVersion = 2;

この部分を3に変更すると、最初からsqlite3が選択された状態になります。
直接3とするのではなく定数で書き直してuser_defined.inc.phpで指定してもいいかもしれませんね。

2011/04/06追記

INSTALLファイルに

5 - Use SQLiteManager with SQLite database version 3
Your php must load at startup the extension : 'php_pdo' and 'php_pdo_sqlite' from PECL
open the user configuration file : user_defined.inc.php
and set
define('SQLITE3', true);
Now all the database must be in version 3
The configuration database is in version 3 too

ってあったけど全然反映されない。そもそもこの定数はどこにも使われていない。

*1:某狐のアレとは別物です。

*2:2011/04/04現在の最新版1.2.4にて確認。

認証用URLを短縮しちゃいかん

認証用URLなんぞをURL短縮サービスで短縮する奴なんかいないだろうと思う方も多いと思いますが、URL短縮について調べていたら、これをやらかしかねない人をちらほら見かけたもので。認証用URLを短縮することの問題点というのを簡単に言うと、攻撃者があてずっぽうで短縮URLにアクセスして認証できてしまう危険性が高いということです。
この問題点の怖いところは、

  1. 長い認証用URLを提供したい「提供者」に悪意がなく、
  2. 長いURLと短縮URLを相互に変換する「短縮者」に問題がなく、
  3. 認証用URLを利用する「利用者」が気をつけていたとしても、

提供者の意識の甘さ一つで利用者のアカウントが攻撃者に乗っ取られる可能性があるということなのです。
提供者というのは例えば何かの会員制サイトであり、短縮者というのは例えばTinyURLやp.tlなどのURL短縮サービスであり、利用者というのは会員制サイトに登録したい人です。

認証用URLというと、利用者が本当に本人による操作なのかを確かめるための長いID(典型的には十数桁以上)が後ろにくっつきます。このIDが長いからこそ攻撃者にはそのIDがわからず、利用者は成りすましの被害を受けることがないのです。これをごっそり取っ払って短縮URLにすると、攻撃者はわずか数文字の予測可能なURLを使うだけで他人の操作を奪取することができるわけです。

では、オンラインショッピングサイトを想定して具体例を見てみましょう。
登場人物は以下のようにします。

  • 提供者:exampleオンラインショップ(www.example.com)
  • 短縮者:example短縮サービス(s.example.com)
  • 利用者:松田さん
  • 攻撃者

ここで、example短縮サービスは、exampleオンラインショップが自社提供しているURL短縮サービスで、exampleオンラインショップだけが使っていることとします。この問題では、短縮URLのパターン数がより少ない自社提供の短縮サービスのほうが大手より危険であるため、このように設定しています。

以下、主語、つまり行動の主体を太字で表記しています。

まず、利用者の松田さんが、exampleオンラインショップに会員登録しようと、会員データとして住所氏名電話番号およびメールアドレスとパスワードをexampleオンラインショップを送信します。もちろん会員データはSSLで暗号化して送られるのでちょっとやそっとじゃ盗聴なんてされないでしょう。

exampleオンラインショップは、松田さんが正しいメールアドレスを登録したかどうか確かめるため、松田さんのメールアドレスに向けて送る認証用URLを生成します。ここでは、出来合いのショッピングサイト構築ソフトが作ったURLにしておきましょう。

ショッピングサイト構築ソフトはきっとだれにも予測できないような認証ID「f6472dd1838795f2be744d3fa602aae3」を生成し、「http://www.example.com/auth.php?authid=f6472dd1838795f2be744d3fa602aae3」なんて長ったらしいURL*1を作り出すことでしょう。この「http://www.example.com/auth.php?authid=f6472dd1838795f2be744d3fa602aae3」にアクセスすれば松田さんは晴れて本会員になり、ログインして松田さんの個人情報を使ってお買い物ができるわけです。
で、exampleオンラインショップは「こんな長いURLなんか送ったら松田さんは大変だろう」などと余計な気を利かせてexample短縮サービスを使ってURLを短縮するわけです。

ここで、example短縮サービスは、短縮URLを「http://s.example.com/(連番)」という形式で作ることにします。たとえば、「http://s.example.com/999」の次は「http://s.example.com/1000」になります。短縮URLやってみようかなって思った人がまず試しそうな素朴な実装*2ですね。

今回、exampleオンラインショップがexample短縮サービスを使うのは6473回目だったとすると、認証用短縮URLは「http://s.example.com/6473」になります。

一方、攻撃者は常日頃からs.example.comをチェックしていて、「http://s.example.com/6472」は既に使われていて「http://s.example.com/6473」はまだ使われていないことを知っていました。つまり、次にURLが短縮されるとしたら必ず「http://s.example.com/6473」になると知っているのです。なので、次に認証用URLが短縮されたら、すでに知っている「http://s.example.com/6473」にアクセスするだけで誰かのアカウントを乗っ取ることができるわけです。

認証用URLが短縮されたらあとは時間との勝負です。

exampleオンラインショップがexample短縮サービスから短縮URLを受け取り、松田さんにメールで短縮URLを送信し、松田さんがメールを受信し、ブラウザを立ち上げ、短縮URLに攻撃者より先にアクセスすると、exampleオンラインショップと松田さんの勝利です。松田さんは本会員となり、認証用URLは無効化*3され、攻撃者は松田さんとして会員になることができず、あきらめて「http://s.example.com/6474」を狙うほかなくなります。

ではもし攻撃者が先に短縮URLにアクセスしたらどうなるでしょう。これは、「http://s.example.com/6473」をブラウザのアドレスバーに入れたまま移動ボタンを何秒かに一回程度押すだけで割と簡単に成功します。もしアクセスしたときまだ認証用URLが有効であれば、攻撃者は松田さんとして本会員になり、松田さんとして松田さんの会員データを使ってお買い物ができるわけです。ついでにパスワードを抜き取れば他のオンラインショップでも使えるかもしれませんね。

このようにして、攻撃者は通信の盗聴すら必要とせず、簡単なURLにアクセスし続けるだけで誰かのアカウントを乗っ取れてしまうということです。そして、利用者の松田さんができる唯一の抵抗は、なるべく早く短縮URLにアクセスすることだけなのです。

ちなみに、松田さん自身が攻撃者と同じ行動をとった場合、認証用URLを記載したメールアドレスを受け取る必要がないので、嘘のメールアドレスで会員登録できてしまいます。これはこれで問題ですね。

効果的ではない対策

この問題は認証IDの情報量がURLからごっそり抜け落ちてしまう点にあるので、情報量を減らしたままではどんな対策も根本的な解決には繋がりません。

大手のURL短縮サービスを使う

自社提供したほうが危険と書きましたが、それは同じ数の攻撃者に同じように狙われていたら、の話です。大手ならば攻撃者の数も当然多いでしょう。

生成される短縮URLを連番以外にする

確かに連番よりは遥かにましになります。しかし、やはり認証IDから減った桁数の分だけ、文字通り桁外れに危険なのです。

認証URLにアクセスしたときパスワードを尋ねる

攻撃者はパスワードを知らないはずなのでアカウントを乗っ取ることはできないでしょう。確かにある意味効果的です。しかしURLを短縮して利便性を図った結果、認証に必要なステップが増えてしまっては、かえって利便性が損なわれるように思います。

また、利用者による嘘のメールアドレス登録も防げないことになります。

認証URLにアクセスしたときIPをチェックする

つまり、登録したときと同じIPならば本人だと判定するという方法です。上記の方法と比べて利便性の問題は解消されていますが、メールアドレスを偽れる問題は残っています。

認証URLを使用する理由を考えると、この方法も効果的ではないことでしょう。

どのように短縮すれば問題ないか

問題点を裏返すと、認証IDの情報量を減らさない限り、いくら短くしても構わないのです。

認証ID以外の部分を短くする

例えば「a.b」というドメインを取得して、「http://a.b/f6472dd1838795f2be744d3fa602aae3」へのアクセスを「http://www.example.com/auth.php?authid=f6472dd1838795f2be744d3fa602aae3」に飛ばすようにすれば、認証IDの安全性を残したままそれなりに短縮できます。

認証IDの冗長性を省く

簡単に言うと、短くても同じだけの情報量を持つように「圧縮」するということです。
例えば、例に使った認証ID「f6472dd1838795f2be744d3fa602aae3」は16進数表記なので、0〜9、a〜fの16種類の文字しか使っていません。g〜zとかA〜Zとか「-」とか「_」とかも使えるのに使っていないから、長くなるのです。
これを、g〜z、A〜Z、「-」、「_」も使って64進数表記*4にすれば、「3ShOThwUulYHVQjj-C0GHz」となります。あまり短くなっていないように思われますが、これでも3割強短縮されています。

終わりに

URL短縮には様々な問題点や危険性が指摘されています(参考:http://goo.gl/fWylz *5 )。しかしそのほとんどは以下の2つのパターンのどちらかでした。

  1. 提供者に悪意があり利用者が被害を受ける(URL隠蔽)
  2. 短縮者に問題があり提供者と利用者の利便性が損なわれる(サービス停止)

これらは、確かにURL短縮にもある問題ですが、根本的には「リダイレクト」一般の問題です。

今回、「URLを短縮すること」そのものによって発生しうる問題について述べました。

実際のところ、認証用URLが短縮されたためにアカウントが乗っ取られたなんて話は聞いたことがありません*6

ただ、これから長いURLを誰かに提供しようとする人は、そのURLを短縮する前に、本当にそのURLは短くても良いのかを考えてみる必要があるでしょう。

*1:今回、authidの値にはPHPのセッションIDを用いました。

*2:素朴な実装ではありますが、短縮すべきURLが多くないと分かっている場合にはこれで充分なのです。今回のような問題が起こらなければ、の話ですが。

*3:さすがにまともなショッピングサイト構築ソフトならこれをやらないなんてことはありえないでしょう。提供者の問題を取り上げているので他はまともであることが大前提です。

*4:BASE64では2種類の記号は「+」と「/」なのですが、URL上で特別な意味を持つ記号なので今回は別の文字を使いました。

*5:「url短縮 危険性 OR リスク OR 問題点」のGoogle検索結果をgoo.glで短縮したものです。

*6:私が短縮URLにさほど深い関心がなく、真剣に探さなかったことも一因でしょうが。

現状FirefoxのHTML ValidatorはHTML5に対応していないらしい

この記事には勘違いが含まれています。読むなら必ず追記まで読んでください。*1
HTML5マークアップされたページがFirefoxFirebugでエラーになった。
日本語で検索したら碌な情報が出なかったので、とりあえず、現状対応していないことだけでもわかったほうがいいと思ってこの記事を作った。
英語なら以下のページで言及されている。
http://www.mail-archive.com/firebug@googlegroups.com/msg05839.html
HTML5に対応したら何か追記しようと思う。

2011/02/11 追記

問題があるのはむしろHTML Validatorのほうだった。道理で情報がないわけだ。
Firebugのほうは今一度確認するとHTML5でもまともに動いているようだった。
HTML5対応のValidatorは別のアドオンが対応しているらしい。
https://addons.mozilla.org/ja/firefox/addon/html-5-validator/
だがまだ開発途上のようだ。

*1:実質追記のほうがメインになったのでタイトルも変更しました。

被告人ドラマ

刑事ドラマがあって、検事ドラマがあって、弁護士ドラマがあって、捜査官ドラマがあって、裁判官ドラマがあって、裁判員ドラマがあって、ふと思ったのです。
裁判をはじめとする法律関係のドラマに被告人ドラマや証人ドラマが見当たらないことに。
例えば、「俺は松田美文。被告人だ。今日も無実の罪で逮捕された。」みたいに始まって毎回無実の罪で起訴される被告人が主人公とか。
そしてドラマが進むに連れて起訴される罪状がどんどんエスカレートするとか。

最終回、巨大な組織の国家的犯罪の濡れ衣を着せられた松田美文、果たして無罪を勝ち取ることができるのか!
窃盗から始まり殺人にいたるまで数々の濡れ衣が、巨大な陰謀へと繋がっていく!!

意外といいと思うのですが、誰かやらないでしょうかねぇ。