岩本隆史の日記帳(アーカイブ)

はてなダイアリーのサービス終了をうけて移行したものです。更新はしません。

Ruby製Webアプリでの書式チェック用正規表現

制御文字は不許可にすべき

前回の日記で「単なる書式チェック(文字種や長さなどのチェック)なので、アプリの要件にしたがって粛々と行えばよい」と書いた「(c)パラメータ文字列の妥当性検証」であるが、実は考えるべきことがそれなりにある。アプリの要件として、各パラメータの「許容文字種」と「許容文字数」を決める必要があるのだ。

このうち許容文字数については話が簡単である。最短および最長の許容文字数を決め、入力値がそれを外れていたらエラーにすればよいだけだ。

問題は許容文字種である。たとえば電話番号の入力を想定したパラメータ文字列であれば「数字またはハイフン」が許容文字種となるだろう。では住所欄や感想欄はどうか。あらゆる文字を受け入れてよいのだろうか。

もちろんアプリによってはあらゆる文字を受け入れなければならない場合もあるだろう。しかし「第11回■制御文字や不正な文字エンコーディングによるぜい弱性を知ろう | 日経 xTECH(クロステック)」で徳丸浩さんが検討されている通り、いわゆる制御文字は不許可としたほうが無難なはずだ。

Perlでの制御文字チェック例

制御文字のチェック方法は、同じく徳丸さんによる「Perlによる入力値検証」を読むと分かりやすい。記事では、許容文字数のチェックも兼ねて下記の正規表現を使っている。

チェック内容 正規表現
制御文字以外100文字以下 /\A\P{Cc}{0,100}\z/
制御文字以外100文字以下
ただし,改行とタブは認める
/\A[\t\r\n\P{Cc}]{0,100}\z/

さて、いよいよ本題である。今回の日記で書きたかったのは以下の2点についてだ。

  • 不許可とすべき制御文字は「Cc」だけか
  • Rubyではどのような正規表現を使えばよいか

不許可とすべき制御文字は「Cc」だけか

徳丸さんの正規表現例で使われている「Cc」はUnicodeのGeneral Categoryの一種である。General Categoryとは各文字に割り当てられるプロパティのひとつで、文字の種別を表したものだ。説明を簡単にするためPHPマニュアルの「Unicode 文字プロパティ」をご覧いただきたい。たとえば大文字アルファベットのGeneral Categoryは「Lu」、10進数字は「Nd」となる。

以下は自作アプリの要件に含めようと考えているだけで声高に主張するわけではないのだが、「Cc」以外の「C」、すなわち「Cf」「Cn」「Co」「Cs」も不許可としてよいのではないか。特に「Cf」には、問題を起こしやすいU+FEFFやU+202Eが含まれている(参考)。

また「Zl」「Zp」も不許可として構わないだろう。現時点で入力値に使われることは考えにくいからだ。

Rubyではどのような正規表現を使えばよいか

Ruby 1.9正規表現エンジンである鬼車のドキュメントFork版鬼車のドキュメントには「Cc」のようなプロパティ指定が使えると書かれている。したがって上記徳丸さんの正規表現Ruby 1.9では問題なく使える。

鬼車ではさらに「Cc」「Cf」「Cn」「Co」「Cs」の総称「C」も使えるし、文字クラスのネストも使える。

よって、Ruby製の自作アプリでは以下のような正規表現を使うことになるだろう。

チェック内容 正規表現
制御文字以外100文字以下 /\A[^\p{C}\p{Zl}\p{Zp}]{0,100}\z/
制御文字以外100文字以下
ただし,改行とタブは認める
/\A[\t\r\n[^\p{C}\p{Zl}\p{Zp}]]{0,100}\z/

実際には、クライアントに的確なエラーメッセージを返すため、文字種のチェックと文字数のチェックは分けて行うべきかもしれない。まとめてチェックすると、どこで引っかかったのかが分からないからだ。

追記(2011-08-10)

Rubyが使っている鬼車がFork版だとわかったので、記事の一部を訂正しました。http://redmine.ruby-lang.org/issues/1889#note-28 にて、まつもとさんが「Our Oniguruma is forked one」とおっしゃっています。

ちなみに鬼車5.x系をRuby 1.9が取り込むにあたっては、Matzにっき(2007-05-25)のような問題がありました。以降の経緯は調べていませんが、結局Forkしたんですね。