Feature #542

cgi.rb : CGI::unescape return encoding

Added by Takeyuki Fujioka over 3 years ago. Updated 10 months ago.

[ruby-dev:36132]
Status:Rejected Start date:09/03/2008
Priority:Normal Due date:
Assignee:Takeyuki Fujioka % Done:

0%

Category:-
Target version:-

Description

CGI::unescapeは現在は引数のencodingでforce_encodingするように
なっていますが、ascii_only?がtrueの場合はUS-ASCII、
falseの場合はASCII-8BITを返すのがいいと思います。

Index: lib/cgi.rb
===================================================================
--- lib/cgi.rb	(リビジョン 19071)
+++ lib/cgi.rb	(作業コピー)
@@ -349,10 +349,10 @@
   #   string = CGI::unescape("%27Stop%21%27+said+Fred")
   #      # => "'Stop!' said Fred"
   def CGI::unescape(string)
-    enc = string.encoding
-    string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
-      [$1.delete('%')].pack('H*').force_encoding(enc)
+    str=string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/) do
+      [$1.delete('%')].pack('H*')
     end
+    str.ascii_only? ? str.force_encoding("US-ASCII") : str.force_encoding("ASCII-8BIT")
   end

   TABLE_FOR_ESCAPE_HTML__ = {

History

Updated by Takeyuki Fujioka over 3 years ago

この修正のテストを追加
Index: test/cgi/test_cgi_class_method.rb
===================================================================
--- test/cgi/test_cgi_class_method.rb	(リビジョン 0)
+++ test/cgi/test_cgi_class_method.rb	(リビジョン 0)
@@ -0,0 +1,21 @@
+require 'test/unit'
+require 'cgi'
+
+
+class CGIClassMethodTest < Test::Unit::TestCase
+  def test_cgi_class_method_escape
+    assert_equal(CGI::unescape("Hello"),"Hello")
+    assert_equal(CGI::unescape("Hello%21%22%25%26%27%28%29-%3D%5E%7E%7C"),
+      "Hello!\"#$\%&'()-=^~|")
+    unescaped=CGI::unescape("%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF")
+    assert_equal(unescaped,"\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF")
+    if RUBY_VERSION>="1.9.0"
+      assert_equal(CGI::unescape("Hello").encoding,Encoding::US_ASCII)
+      assert_equal(CGI::unescape("Hello%21%22%25%26%27%28%29-%3D%5E%7E%7C").encoding,
+                   Encoding::US_ASCII)
+      assert_equal(unescaped.encoding,Encoding::ASCII_8BIT)
+    end
+  end
+end
+
+

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> CGI::unescapeは現在は引数のencodingでforce_encodingするように
>> なっていますが、ascii_only?がtrueの場合はUS-ASCII、
>> falseの場合はASCII-8BITを返すのがいいと思います。
> 
> 引数にもともと非ASCII文字が入っていた場合にはどうなりますかね。

その部分は何も変換されません。
エンコーディングはASCII-8BITになります。

Updated by Yui NARUSE over 3 years ago

成瀬です。

Takeyuki Fujioka wrote:
> CGI::unescapeは現在は引数のencodingでforce_encodingするように
> なっていますが、ascii_only?がtrueの場合はUS-ASCII、
> falseの場合はASCII-8BITを返すのがいいと思います。

ascii_only? なときに US-ASCII を返すのはいいと思うのですが、
false なときに ASCII-8BIT はまずいですね。

HTTP ヘッダで charset を指定されつつ escape されて渡された場合、
とりあえず escape された文字列にその charset をつけ、
その後に unescape するってのはそれなりにありうる流れなので。

Ruby M17N では、一連の処理の結果の encoding を指定する際に、
引数の String#encodig を用いるということはしばしば行われます。

-- 
NARUSE, Yui  <naruse@airemix.jp>

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

Fujioka wrote:
>> CGI::unescapeは現在は引数のencodingでforce_encodingするように
>> なっていますが、ascii_only?がtrueの場合はUS-ASCII、
>> falseの場合はASCII-8BITを返すのがいいと思います。
> 
> ascii_only? なときに US-ASCII を返すのはいいと思うのですが、
> false なときに ASCII-8BIT はまずいですね。
> 
> HTTP ヘッダで charset を指定されつつ escape されて渡された場合、
> とりあえず escape された文字列にその charset をつけ、
> その後に unescape するってのはそれなりにありうる流れなので。
> 
クエリを渡された場合はそのクエリにencodingをつけて
unescapeするのではなくて、unescapeをしてから
encodingをつけるのが順番としては正しいと思います。
クエリは通常はascii文字列のはずなので、
それにencodingをつける方が間違っていると思います。

ただ、今思っているのはASCII以外はASCII-8BITになるのは
あんまりだと思っていて、CGI.newしたときにオプションで
期待するencodingを渡してあげれば
自動的にUS-ASCIIかそれ以外の場合はそのencodingにforce_encodingして
あげる機能が欲しいと思っています。
まだ抗争中ですが。

> Ruby M17N では、一連の処理の結果の encoding を指定する際に、
> 引数の String#encodig を用いるということはしばしば行われます。
> 
unescapeはasciiからasciiかどうかわからない文字列へのフィルタなので
引数のencodingはあてにできないと思っています。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> その部分は何も変換されません。
>> エンコーディングはASCII-8BITになります。
> 
> [ruby-dev:36138] の実装は (引数が ASCII-8BIT 以外で非ASCII文
> 字が入っていれば) 例外になりそうですが、そんなことはありませ
> んか?

つまりencodingが間違っている場合ということですか?
その場合は例外でもいいような。。。
ASCII-8BITに変換してから処理して例外を出さない方がいいでしょうか?

Updated by Koichi Sasada over 3 years ago

  • Assignee set to Takeyuki Fujioka

Updated by Takeyuki Fujioka over 3 years ago

  • Status changed from Open to Rejected
いずれencodingの自動付与機能を搭載するということで、
このチケットは閉じます。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> 成瀬さんとやり取りをした結果、やはりヘッダのcharsetを見て
>> そのencodingをつけてあげるのが筋だろうという話になりました。
> 
> ブラウザはここで利用できる charset をつけてくれるんでしょう
> か?

いえ、つけてくれません。
あくまでCGIアプリ側が期待することになります。

でも、例えばUTF-8を期待しているアプリにEUC-JPをポストして
例外が起きるのは好ましくありませんね。考えます。

Updated by Toru Iwase over 3 years ago

On Wed, 10 Sep 2008 13:51:26 +0900
In article <87ej3stx68.fsf@fsij.org>
[[ruby-dev:36239] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Tanaka Akira <akr@fsij.org> wrote:

> In article <48C0C20E.4000307@rabbix.jp>,
>   Fujioka <fuj@rabbix.jp> writes:
> 
> > 成瀬さんとやり取りをした結果、やはりヘッダのcharsetを見て
> > そのencodingをつけてあげるのが筋だろうという話になりました。
> 
> ブラウザはここで利用できる charset をつけてくれるんでしょう
> か?

application/x-www-form-urlencoded にはそもそも charset がありませんし、
multipart/form-data にも charset が付いているのは見たことがないです。



-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Toru Iwase over 3 years ago

On Wed, 10 Sep 2008 14:33:34 +0900
In article <48C75DB4.5010908@rabbix.jp>
[[ruby-dev:36241] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Fujioka <fuj@rabbix.jp> wrote:

> でも、例えばUTF-8を期待しているアプリにEUC-JPをポストして
> 例外が起きるのは好ましくありませんね。考えます。

期待しているのと違う文字セット、あるいは壊れた文字列を渡し、XSSを起こす
という攻撃があるので、むしろ例外の方がありがたいかもしれません。

begin
  cgi = CGI.new(:assume_encoding => 'UTF-8')
rescue CGI::InvalidEncodingError
  print "Status: 400 Bad Request\n\n"
  exit
end


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>>> 成瀬さんとやり取りをした結果、やはりヘッダのcharsetを見て
>>> そのencodingをつけてあげるのが筋だろうという話になりました。
>> ブラウザはここで利用できる charset をつけてくれるんでしょう
>> か?
> 
> application/x-www-form-urlencoded にはそもそも charset がありませんし、
> multipart/form-data にも charset が付いているのは見たことがないです。
> 
encoding情報はもらえないので、期待するしかないです。
だからといってASCII-8BITかUS-ASCIIのどちらでしか
データを貰えないというのも面倒かなと思うのですが、
どうしたらいいと思いますか?

ポストされたデータは

1.ASCII-8BIT でもらう(現状)
2.US-ASCII or ASCII-8BIT でもらう
3.期待するencodingを決めて、US-ASCII or 期待するencodingでもらう
4.上記3に加えて、encodingチェックをおこなって、encodingが間違っている
  場合はnilなどを返す

1と2は日本語のCGIアプリの出力が面倒です。
@cgi=CGI.new
したとして、ポストされたデータに日本語が入ってくると
"タイトル:#{@cgi['title']}"
これが例外です。
日本語文字列とASCII-8BITが連結できないためです。
これでは使いづらいなぁと思ってアイディアを模索している最中です。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

Tanaka Akira さんは書きました:
>> encoding情報はもらえないので、期待するしかないです。
>> だからといってASCII-8BITかUS-ASCIIのどちらでしか
>> データを貰えないというのも面倒かなと思うのですが、
>> どうしたらいいと思いますか?
> 
> アプリケーションが期待するエンコーディングを cgi.rb に
> 教えてやるしかないし、そうするのが良いと思います。
> 
了解です。

> 仕様としてはブラウザがデータを送ってくる原因となった HTML の
> form の accept-charset を cgi.rb に
> 教えてやる (ということにしておく) んじゃないでしょうか。
> 
送られてくるFormにaccept-charsetをつけても、
IEもFirefoxも対応していないので、実質無意味だと思います。
hidden属性でaccept-charsetを送るということですか?
それだったら現実的かな。

> まぁ、accept-charset に限らず form の情報を教えてやるといろ
> いろ検査できていいかもしれませんが。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

> Web サーバが form を含む HTML を送った時に、ブラウザがどのよ
> うな charset で返事を Web サーバ返すべきかを accept-charset
> のような明示的な形や、HTML 自体の encoding として暗黙な形で
> 指示しているので、その指示を cgi.rb に教えてやるという意味を
> 意図していました。
> 
> なお、手元の iceweasel 2.0.0.16 は accept-charset を理解して
> 従うようです。
> 
やはり、明示的にcgi.rbのインスタンスに伝えておいた方がよさそうですね。
エラー処理とか何もまだないですが、
とりあえず下のパッチで以下のようなCGIアプリは動きます。
この方針としてはいかがでしょうか?>ほかの意見ありそうな方々

あと、エンコーディングが違う文字列を送りつけられた場合に
どうするかですが、
1. 放置(おそらくどこかで例外を起こして止まる)
2. 検証しておかしかったときはkeyごと無視する
3. 検証しておかしかったときはkeyはあるけど中身をnilにする
4. 検証しておかしかったときはvalueをASCII-8BITにしてしまう
4が親切かなと思うのですが、ご意見よろしくお願いします。

#!/Users/fujioka/local/bin/ruby19
# vim:fileencoding=UTF-8
require 'cgi'
@cgi=CGI.new("html3","UTF-8")
@header = { "type" => "text/html", "charset" => "UTF-8" }

@cgi.out(@header) do
  @cgi.html do
    @cgi.head{@cgi.title{"たいとる"}}+
      @cgi.body do
        "結果:#{@cgi['title']}"+
          @cgi.form("action"=>@cgi.script_name) do
            @cgi.text_field("name"=>"title")+
            @cgi.hidden("name"=>"key","value"=>"value")+
              @cgi.submit("value"=>"OK")
          end
      end
  end
end

Index: lib/cgi/core.rb
===================================================================
--- lib/cgi/core.rb	(revision 19280)
+++ lib/cgi/core.rb	(working copy)
@@ -600,7 +600,7 @@

stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
                     else
                       read_from_cmdline
-                    end
+                    end.force_encoding(@encoding)
                   )
       end

@@ -667,7 +667,8 @@
   # from the command line or (failing that) from standard input.
Otherwise,
   # cookies and other parameters are parsed automatically from the standard
   # CGI locations, which varies according to the REQUEST_METHOD.
-  def initialize(type = "query")
+  def initialize(type = "query",encoding="ASCII-8BIT")
+    @encoding=encoding
     if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
       Apache.request.setup_cgi_env
     end

Updated by Kazuhiro NISHIYAMA over 3 years ago

西山和広です。

At Sun, 14 Sep 2008 00:27:27 +0900,
Fujioka wrote:
> 
> あと、エンコーディングが違う文字列を送りつけられた場合に
> どうするかですが、
> 1. 放置(おそらくどこかで例外を起こして止まる)
> 2. 検証しておかしかったときはkeyごと無視する
> 3. 検証しておかしかったときはkeyはあるけど中身をnilにする
> 4. 検証しておかしかったときはvalueをASCII-8BITにしてしまう
> 4が親切かなと思うのですが、ご意見よろしくお願いします。

バイナリファイルのアップロードをするときに2や3だと困りそうです。


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

Updated by Toru Iwase over 3 years ago

On Tue, 16 Sep 2008 17:33:08 +0900
In article <85r67k4h6t.wl%zn@mbf.nifty.com>
[[ruby-dev:36321] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Kazuhiro NISHIYAMA <zn@mbf.nifty.com> wrote:

> > あと、エンコーディングが違う文字列を送りつけられた場合に
> > どうするかですが、
> > 1. 放置(おそらくどこかで例外を起こして止まる)
> > 2. 検証しておかしかったときはkeyごと無視する
> > 3. 検証しておかしかったときはkeyはあるけど中身をnilにする
> > 4. 検証しておかしかったときはvalueをASCII-8BITにしてしまう
> > 4が親切かなと思うのですが、ご意見よろしくお願いします。
> 
> バイナリファイルのアップロードをするときに2や3だと困りそうです。

multipart/form-data で、かつ Content-Disposition filename を持っていれば 
ASCII-8BIT で、そうでなければ検証 とか。


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> あと、エンコーディングが違う文字列を送りつけられた場合に
>> どうするかですが、
>> 1. 放置(おそらくどこかで例外を起こして止まる)
>> 2. 検証しておかしかったときはkeyごと無視する
>> 3. 検証しておかしかったときはkeyはあるけど中身をnilにする
>> 4. 検証しておかしかったときはvalueをASCII-8BITにしてしまう
>> 4が親切かなと思うのですが、ご意見よろしくお願いします。
> 
> バイナリファイルのアップロードをするときに2や3だと困りそうです。
> 
ファイルは受取encodingが指定されていてもASCII-8BITが
適切じゃないかと思います。
ファイル以外の話だったら2とか3はいかがでしょう?

Updated by Yui NARUSE over 3 years ago

成瀬です。

Fujioka wrote:
> あと、エンコーディングが違う文字列を送りつけられた場合に
> どうするかですが、
> 1. 放置(おそらくどこかで例外を起こして止まる)
> 2. 検証しておかしかったときはkeyごと無視する
> 3. 検証しておかしかったときはkeyはあるけど中身をnilにする
> 4. 検証しておかしかったときはvalueをASCII-8BITにしてしまう
> 4が親切かなと思うのですが、ご意見よろしくお願いします。

5. かまわず指定された encoding をつける

じゃないですかね。
String#valid_encoding? で調べるとか、後で対処する方法はあるのですから。

-- 
NARUSE, Yui  <naruse@airemix.jp>

Updated by Yui NARUSE over 3 years ago

成瀬です。

Fujioka wrote:
>>> あと、エンコーディングが違う文字列を送りつけられた場合に
>>> どうするかですが、
>>> 1. 放置(おそらくどこかで例外を起こして止まる)
>>> 2. 検証しておかしかったときはkeyごと無視する
>>> 3. 検証しておかしかったときはkeyはあるけど中身をnilにする
>>> 4. 検証しておかしかったときはvalueをASCII-8BITにしてしまう
>>> 4が親切かなと思うのですが、ご意見よろしくお願いします。
>> バイナリファイルのアップロードをするときに2や3だと困りそうです。
>>
> ファイルは受取encodingが指定されていてもASCII-8BITが
> 適切じゃないかと思います。
> ファイル以外の話だったら2とか3はいかがでしょう?

バイナリファイルだったら ASCII-8BIT がよいですし、
テキストファイルならエンコーディング固定かもしれないわけで、
これも別途受け取り encoding を指定させるべきでしょう。

-- 
NARUSE, Yui  <naruse@airemix.jp>

Updated by Toru Iwase over 3 years ago

On Tue, 16 Sep 2008 21:37:12 +0900
In article <48CFAA31.1080709@airemix.jp>
[[ruby-dev:36332] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
"NARUSE, Yui" <naruse@airemix.jp> wrote:

> 5. かまわず指定された encoding をつける
> 
> じゃないですかね。
> String#valid_encoding? で調べるとか、後で対処する方法はあるのですから。

bad knowhow になりそうで怖いです。

cgi = CGI.new('UTF-8')
unless cgi.param.join.valid_encoding?
  print cgi.header('status' => '400 Bad Request')
  print 'Bad Request'
  exit
end

等のコードを毎度書くか俺ライブラリにする必要があるわけで。




-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> 5. かまわず指定された encoding をつける
>>
>> じゃないですかね。
>> String#valid_encoding? で調べるとか、後で対処する方法はあるのですから。
> 
> bad knowhow になりそうで怖いです。
> 
bad knowhowになるぐらいだったら実装したいですね。

> cgi = CGI.new('UTF-8')
> unless cgi.param.join.valid_encoding?
>   print cgi.header('status' => '400 Bad Request')
>   print 'Bad Request'
>   exit
> end
> 
> 等のコードを毎度書くか俺ライブラリにする必要があるわけで。
> 
これだとEUC-JPとUTF-8を送りつけられたときにjoinの時点で例外なような。
という話はさておき、
newするときのオプションで期待する挙動を切り替えられると
使いやすいでしょうかね?

cgi=CGI.new(:encoding=>"UTF-8",:element_encoding_check=>true)

みたいに。

Updated by Toru Iwase over 3 years ago

On Wed, 17 Sep 2008 11:49:12 +0900
In article <48D071E7.1090907@rabbix.jp>
[[ruby-dev:36342] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Fujioka <fuj@rabbix.jp> wrote:

> 藤岡です。
> 
> >> 5. かまわず指定された encoding をつける
> >>
> >> じゃないですかね。
> >> String#valid_encoding? で調べるとか、後で対処する方法はあるのですから。
> > 
> > bad knowhow になりそうで怖いです。
> > 
> bad knowhowになるぐらいだったら実装したいですね。
> 
> > cgi = CGI.new('UTF-8')
> > unless cgi.param.join.valid_encoding?
> >   print cgi.header('status' => '400 Bad Request')
> >   print 'Bad Request'
> >   exit
> > end
> > 
> > 等のコードを毎度書くか俺ライブラリにする必要があるわけで。
> > 
> これだとEUC-JPとUTF-8を送りつけられたときにjoinの時点で例外なような。

force_encoding されている、という前提なので、例外はないはず。

> newするときのオプションで期待する挙動を切り替えられると
> 使いやすいでしょうかね?
> 
> cgi=CGI.new(:encoding=>"UTF-8",:element_encoding_check=>true)

デフォルトチェックを希望。
混在したor不正なエンコーディングを受け付けることの方が例外的だと思います。
アップロードされたバイナリはもともと除外な訳で。


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>>>> 5. かまわず指定された encoding をつける
>>>>
>>>> じゃないですかね。
>>>> String#valid_encoding? で調べるとか、後で対処する方法はあるのですから。
>>> bad knowhow になりそうで怖いです。
>>>
>> bad knowhowになるぐらいだったら実装したいですね。
>>
>>> cgi = CGI.new('UTF-8')
>>> unless cgi.param.join.valid_encoding?
>>>   print cgi.header('status' => '400 Bad Request')
>>>   print 'Bad Request'
>>>   exit
>>> end
>>>
>>> 等のコードを毎度書くか俺ライブラリにする必要があるわけで。
>>>
>> これだとEUC-JPとUTF-8を送りつけられたときにjoinの時点で例外なような。
> 
> force_encoding されている、という前提なので、例外はないはず。
> 
>> newするときのオプションで期待する挙動を切り替えられると
>> 使いやすいでしょうかね?
>>
>> cgi=CGI.new(:encoding=>"UTF-8",:element_encoding_check=>true)
> 
> デフォルトチェックを希望。
> 混在したor不正なエンコーディングを受け付けることの方が例外的だと思います。
> アップロードされたバイナリはもともと除外な訳で。
> 
私としてはチェックを入れた方がいいと思っています。
cgi=CGI.new(:encoding=>"UTF-8",:element_encoding_check=>false)
こんな感じでできると楽かなと。
ファイルに関してはすべてASCII-8BITがいいと思っています。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

> 私としてはチェックを入れた方がいいと思っています。
> cgi=CGI.new(:encoding=>"UTF-8",:element_encoding_check=>false)
> こんな感じでできると楽かなと。
> ファイルに関してはすべてASCII-8BITがいいと思っています。
> 
* CGI.newのオプションでHashも取れるようにする
 (現状は"html3"などのStringのみ)
* CGIに@@encodingというクラス変数を用意し、default値は"UTF-8"とする
* CGI::encodingとCGI::encoding=というメソッドを用意し、
 @@encodingのセッターとゲッターにする
* CGI.newされたときにオプションで
 CGI.new(:encoding=>"EUC-JP")などと指定されない場合は
 @@encodingの値を@encodingに代入する
* 各々のエレメントの値は@encodingの値でforce_encodingし、
 valid_encoding?する。ただし、fileだけはASCII-8BITとする。
* オプションのときに:element_encoding_check=>falseが与えられたときは
 エンコーディングチェックしない。
* encodingのチェックをして正しくない場合はASCII-8BITに
 force_encodingしてしまう

以上のような仕様ではいかがでしょうか?
サンプルベースで行くと、

require 'cgi'
@cgi=CGI.new("html3")

とやった場合は受け取った値はUTF-8とみなし、encodingのチェックを入れる。
タグメーカーはhtml3とする。
EUC-JPにする場合は

require 'cgi'
CGI::encoding="EUC-JP"
@cgi=CGI.new("html3")

もしくは

require 'cgi'
@cgi=CGI.new(:tag_maker=>"html3",:encoding=>"EUC-JP")

とする。エンコーディングのチェックをしない場合は

require 'cgi'
@cgi=CGI.new(:tag_maker=>"html3",:encoding=>"EUC-JP",:element_encoding_check=>false)

といったようにインスタンスへオプションで渡す。
以上のような使い勝手になります。

Updated by Kazuhiro NISHIYAMA over 3 years ago

西山和広です。

At Sun, 21 Sep 2008 15:17:28 +0900,
Fujioka wrote:
> 
> * 各々のエレメントの値は@encodingの値でforce_encodingし、
>  valid_encoding?する。ただし、fileだけはASCII-8BITとする。

ファイルかどうかはどうやって判断するのでしょうか?


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

> At Sun, 21 Sep 2008 15:17:28 +0900,
> Fujioka wrote:
>> * 各々のエレメントの値は@encodingの値でforce_encodingし、
>>  valid_encoding?する。ただし、fileだけはASCII-8BITとする。
> 
> ファイルかどうかはどうやって判断するのでしょうか?
> 
finenameがあったらASCII-8BIT固定にするのがいいかなと思っています。
ファイルも特別扱いしない方がいいと思いますか?

Updated by Yui NARUSE over 3 years ago

成瀬です。

Fujioka さんは書きました:
> 藤岡です。
> 
>> At Sun, 21 Sep 2008 15:17:28 +0900,
>> Fujioka wrote:
>>> * 各々のエレメントの値は@encodingの値でforce_encodingし、
>>>  valid_encoding?する。ただし、fileだけはASCII-8BITとする。
>> ファイルかどうかはどうやって判断するのでしょうか?
>>
> finenameがあったらASCII-8BIT固定にするのがいいかなと思っています。
> ファイルも特別扱いしない方がいいと思いますか?

Content-Type を見ればデータが文字列かバイナリかはわかるので、
それを見るのがいいのではないでしょうか。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> finenameがあったらASCII-8BIT固定にするのがいいかなと思っています。
>> ファイルも特別扱いしない方がいいと思いますか?
> 
> Content-Type を見ればデータが文字列かバイナリかはわかるので、
> それを見るのがいいのではないでしょうか。
> 
投稿してから私もそのほうがいいなと思っていました。
Content-Typeを見るように作ってみます。

Updated by Kazuhiro NISHIYAMA over 3 years ago

西山和広です。

At Mon, 22 Sep 2008 01:11:44 +0900,
Fujioka wrote:
> 
> >> finenameがあったらASCII-8BIT固定にするのがいいかなと思っています。
> >> ファイルも特別扱いしない方がいいと思いますか?
> > 
> > Content-Type を見ればデータが文字列かバイナリかはわかるので、
> > それを見るのがいいのではないでしょうか。
> > 
> 投稿してから私もそのほうがいいなと思っていました。
> Content-Typeを見るように作ってみます。

受け取るCGI側ではなく送るUser-Agent側でASCII-8BITになるかどうか
決められると言うことは、encodingのチェックをすり抜けられるリクエストを
送りつけられると言うことになりそうですが、セキュリティ的に問題は
ないのでしょうか?


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>>>> finenameがあったらASCII-8BIT固定にするのがいいかなと思っています。
>>>> ファイルも特別扱いしない方がいいと思いますか?
>>> Content-Type を見ればデータが文字列かバイナリかはわかるので、
>>> それを見るのがいいのではないでしょうか。
>>>
>> 投稿してから私もそのほうがいいなと思っていました。
>> Content-Typeを見るように作ってみます。
> 
> 受け取るCGI側ではなく送るUser-Agent側でASCII-8BITになるかどうか
> 決められると言うことは、encodingのチェックをすり抜けられるリクエストを
> 送りつけられると言うことになりそうですが、セキュリティ的に問題は
> ないのでしょうか?
> 
エンコーディングのチェックはあくまで使い勝手の問題の話であって
セキュリティチェックのつもりはなかったので、問題ないと思っていました。
現状のcgi.rbではエンコーディングチェックは存在せず、
送りつけられたものはオブジェクトを生成します。
これをチェックするとしたら、
CGI.newでオプテョンを渡して受け取るエレメントとエンコーディングを
逐一指定する必要が出てきます。
そうなると使い勝手が悪いかなと思っています。

Updated by Toru Iwase over 3 years ago

On Mon, 22 Sep 2008 01:11:44 +0900
In article <48D67424.2060409@rabbix.jp>
[[ruby-dev:36430] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Fujioka <fuj@rabbix.jp> wrote:

> 投稿してから私もそのほうがいいなと思っていました。
> Content-Typeを見るように作ってみます。
> 
通常のフィールドではContent-Typeは渡されませんが、ファイルの場合は 
Content-Type:text/plain なんてこともあり得ます。
Content-Typeの有無は信頼性がないと思います。


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Toru Iwase over 3 years ago

On Sun, 21 Sep 2008 15:17:28 +0900
In article <48D5E8D8.2030205@rabbix.jp>
[[ruby-dev:36422] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Fujioka <fuj@rabbix.jp> wrote:

> * encodingのチェックをして正しくない場合はASCII-8BITに
>  force_encodingしてしまう

例外を起こすか、何らかの形で「不正エンコーディングを検出した」ということ
を検出できる方法が欲しいです。

# 不正エンコーディングを検出したら 400 等のステータスで即終了。


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>> 投稿してから私もそのほうがいいなと思っていました。
>> Content-Typeを見るように作ってみます。
>>
> 通常のフィールドではContent-Typeは渡されませんが、ファイルの場合は 
> Content-Type:text/plain なんてこともあり得ます。
> Content-Typeの有無は信頼性がないと思います。
> 
Content-Typeがあればファイルとみなすつもりでした。


>> * encodingのチェックをして正しくない場合はASCII-8BITに
>>  force_encodingしてしまう
>
> 例外を起こすか、何らかの形で「不正エンコーディングを検出した」ということ
> を検出できる方法が欲しいです。
>
> # 不正エンコーディングを検出したら 400 等のステータスで即終了。
>
即終了するのはそのようにコーディングしてもらうとして、
何らかの形の部分の希望はありますか?
例えば@encoding_errorsのarrayを作って項目名をプッシュするとか

Updated by Toru Iwase over 3 years ago

On Mon, 22 Sep 2008 11:22:44 +0900
In article <48D7035D.3020404@rabbix.jp>
[[ruby-dev:36436] Re: [Feature #542] cgi.rb : CGI::unescape return encoding]
Fujioka <fuj@rabbix.jp> wrote:

> >> 投稿してから私もそのほうがいいなと思っていました。
> >> Content-Typeを見るように作ってみます。
> >>
> > 通常のフィールドではContent-Typeは渡されませんが、ファイルの場合は 
> > Content-Type:text/plain なんてこともあり得ます。
> > Content-Typeの有無は信頼性がないと思います。
> > 
> Content-Typeがあればファイルとみなすつもりでした。

Content-Type の有無でファイルか否かは検出できなかったような。


> >> * encodingのチェックをして正しくない場合はASCII-8BITに
> >>  force_encodingしてしまう
> >
> > 例外を起こすか、何らかの形で「不正エンコーディングを検出した」ということ
> > を検出できる方法が欲しいです。
> >
> > # 不正エンコーディングを検出したら 400 等のステータスで即終了。
> >
> 即終了するのはそのようにコーディングしてもらうとして、
> 何らかの形の部分の希望はありますか?
> 例えば@encoding_errorsのarrayを作って項目名をプッシュするとか

個人的には、どのフィールドが不正なのかということに興味はないので、
true/false が返る程度で構いません。他の人の意見も聞きたいです。

抜け穴を防ぐという意味では例外の方がいいのかなあ。


-- 
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153  81C4 773C 963A D51B 8CAA

Updated by Kazuhiro NISHIYAMA over 3 years ago

西山和広です。

At Mon, 22 Sep 2008 18:55:07 +0900,
Tietew wrote:
> 
> > >> * encodingのチェックをして正しくない場合はASCII-8BITに
> > >>  force_encodingしてしまう
> > >
> > > 例外を起こすか、何らかの形で「不正エンコーディングを検出した」ということ
> > > を検出できる方法が欲しいです。
> > >
> > > # 不正エンコーディングを検出したら 400 等のステータスで即終了。
> > >
> > 即終了するのはそのようにコーディングしてもらうとして、
> > 何らかの形の部分の希望はありますか?
> > 例えば@encoding_errorsのarrayを作って項目名をプッシュするとか
> 
> 個人的には、どのフィールドが不正なのかということに興味はないので、
> true/false が返る程度で構いません。他の人の意見も聞きたいです。
> 
> 抜け穴を防ぐという意味では例外の方がいいのかなあ。

不正エンコーディングを検出したときに実行するブロックを指定できる
ようにして、指定がなかった場合のデフォルトは例外で、どのフィールドか
知りたければそこで残すようにするとか?


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

> CGI.new(:accept_encoding=>"...",
>   "name1"=>:file,
>   "name2"=>...)
> 
> で、検査しないなら
> 
> CGI.new(:accept_encoding=>:no_validation,
>   "name1"=>:file,
>   "name2"=>...)
> 
> とか。

こんな感じで項目毎にチェックを要求すると、
今あるウェブアプリ(tDiaryやHikiなども含む)は
軒並み設計をし直しになると思います。
理由はたいていのアプリはcgi=CGI.newをアプリの最初にやっておいて、
それからcgiを引き回す設計になっているからです。
また、CGI.newしたときにクエリをパースしているのですが、
CGI.newする前にURLはわかっていませんので、
どの項目を受け取れるようにするかを知らせることが困難です。
だからといって、ウェブアプリで使う項目を全部書くのも
現実的ではありませんし、動的な名前が受け付けられないのも困ります。
そのため、私は各項目名毎のチェックは入れたくありません。
セキュリティ的に問題だとしたら、容量チェックや
項目数の上限を設定する方が、
使い勝手の面でいいのではないかと思っています。

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

>>>>> * encodingのチェックをして正しくない場合はASCII-8BITに
>>>>>  force_encodingしてしまう
>>>> 例外を起こすか、何らかの形で「不正エンコーディングを検出した」ということ
>>>> を検出できる方法が欲しいです。
>>>>
>>>> # 不正エンコーディングを検出したら 400 等のステータスで即終了。
>>>>
>>> 即終了するのはそのようにコーディングしてもらうとして、
>>> 何らかの形の部分の希望はありますか?
>>> 例えば@encoding_errorsのarrayを作って項目名をプッシュするとか
>> 個人的には、どのフィールドが不正なのかということに興味はないので、
>> true/false が返る程度で構いません。他の人の意見も聞きたいです。
>>
>> 抜け穴を防ぐという意味では例外の方がいいのかなあ。
> 
> 不正エンコーディングを検出したときに実行するブロックを指定できる
> ようにして、指定がなかった場合のデフォルトは例外で、どのフィールドか
> 知りたければそこで残すようにするとか?
> 
これ、コードのサンプルを作れませんでしょうか?
こんな風に使いたいみたいなやつ。

Updated by Kazuhiro NISHIYAMA over 3 years ago

西山和広です。

At Mon, 22 Sep 2008 20:17:26 +0900,
Fujioka wrote:
> 
> > 不正エンコーディングを検出したときに実行するブロックを指定できる
> > ようにして、指定がなかった場合のデフォルトは例外で、どのフィールドか
> > 知りたければそこで残すようにするとか?
> > 
> これ、コードのサンプルを作れませんでしょうか?
> こんな風に使いたいみたいなやつ。

Railsでvalidateにひっかかったときに赤い枠がついたりするような感じで
以下のように引っかかったフィールドに何か印をつけるのに使えるかも、
というイメージです。

invalid_fields = {}
cgi = CGI.new(..., :... =>proc {|field_name, field_value|
  invalid_fields[field_name] = field_value
})
...
cgi.out(...) {
  ...
  cgi.text_field({...,"name"=>"some_text", "class"=>
    invalid_fields.include?("some_text") ? "invalid" : ""
  })
  ...
}


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

> Railsでvalidateにひっかかったときに赤い枠がついたりするような感じで
> 以下のように引っかかったフィールドに何か印をつけるのに使えるかも、
> というイメージです。
> 
> invalid_fields = {}
> cgi = CGI.new(..., :... =>proc {|field_name, field_value|
>   invalid_fields[field_name] = field_value
> })
> ...
> cgi.out(...) {
>   ...
>   cgi.text_field({...,"name"=>"some_text", "class"=>
>     invalid_fields.include?("some_text") ? "invalid" : ""
>   })
>   ...
> }
> 
> 
こんな感じでしょうか。
invalid_fields={}
cgi=CGI.new(:accept_charset=>"EUC-JP"){|field_name,field_value|
  invalid_fields[field_name] = field_value
}
こんな感じで使えます。newのブロックに渡すのはいいのかどうか微妙ですが。
メソッドのブロックが空いているので詰め込んでみました。

Index: lib/cgi/core.rb
===================================================================
--- lib/cgi/core.rb	(リビジョン 19454)
+++ lib/cgi/core.rb	(作業コピー)
@@ -598,8 +598,21 @@

stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
                     else
                       read_from_cmdline
-                    end
+                    end.dup.force_encoding(@accept_charset)
                   )
+        if @accept_charset!="ASCII-8BIT" ||
@accept_charset!=Encoding::ASCII_8BIT
+          @params.each do |key,values|
+            values.each do |value|
+              unless value.valid_encoding?
+                if @accept_charset_error_block
+                  @accept_charset_error_block.call(key,value)
+                else
+                  raise "Accept-Charset encoding error"
+                end
+              end
+            end
+          end
+        end
       end

       @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or
env_table['COOKIE']))
@@ -665,7 +678,24 @@
   # from the command line or (failing that) from standard input.
Otherwise,
   # cookies and other parameters are parsed automatically from the standard
   # CGI locations, which varies according to the REQUEST_METHOD.
-  def initialize(type = "query")
+  attr_reader :accept_charset
+  @@accept_charset="UTF-8"
+  def self.accept_charset
+    @@accept_charset
+  end
+  def self.accept_charset=(accept_charset)
+    @@accept_charset=accept_charset
+  end
+  def initialize(options = {},&block)
+    @accept_charset_error_block=block if block_given?
+    @options={:accept_charset=>@@accept_charset}
+    case options
+    when Hash
+      @options.merge!(options)
+    when String
+      @options[:tag_maker]=options
+    end
+    @accept_charset=@options[:accept_charset]
     if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
       Apache.request.setup_cgi_env
     end
@@ -677,7 +707,7 @@
     @output_cookies = nil
     @output_hidden = nil

-    case type
+    case @options[:tag_maker]
     when "html3"
       require 'cgi/html'
       extend Html3

Updated by Takeyuki Fujioka over 3 years ago

藤岡です。

> こんな感じでしょうか。
> invalid_fields={}
> cgi=CGI.new(:accept_charset=>"EUC-JP"){|field_name,field_value|
>   invalid_fields[field_name] = field_value
> }
> こんな感じで使えます。newのブロックに渡すのはいいのかどうか微妙ですが。
> メソッドのブロックが空いているので詰め込んでみました。
> 
大きな反対がなければ明日あたりにとりあえずコミットしてしまう予定です。
マルチパートのほうはまだ何もやっていませんが、
エンコーディング以前に動きそうにないので、
今後対応していきます。

Also available in: Atom PDF