From: Makoto Kuwata Date: 2008-02-06T02:06:34+09:00 Subject: [ruby-dev:33606] Re: cgi.rb再構築案 桑田といいます。 2008/2/4 Yukihiro Matsumoto : > > パッチを用意してくだされば取り込みます。 > CGI::Cookieを、DelegateClass(Array) を使わないように するためのpatch (for 1.8.6 p111) です。 Index: lib/cgi.rb =================================================================== --- lib/cgi.rb (revision 15382) +++ lib/cgi.rb (working copy) @@ -736,7 +736,6 @@ stdoutput.print(*options) end - require "delegate" # Class representing an HTTP cookie. # @@ -771,7 +770,7 @@ # cookie1.domain = 'domain' # cookie1.expires = Time.now + 30 # cookie1.secure = true - class Cookie < DelegateClass(Array) + class Cookie # Create a new CGI::Cookie object. # @@ -858,6 +857,36 @@ buf end + ##-- + ## define methods instead of DelegateClass(Array) + ##++ + + include Enumerable ##:nodoc: + + def [](*args) ##:nodoc: + @value[*args] + end + + def []=(index, value) ##:nodoc: + @value[index] = value + end + + def each(&block) ##:nodoc: + @value.each(&block) + end + + def method_missing(m, *args) ##:nodoc: + @value.respond_to?(m) ? @value.__send__(m, *args) : super + end + + def respond_to?(m) ##:nodoc: + super(m) || @value.respond_to?(m) + end + + #def inspect; @value.inspect; end + #def ==(arg); @value == arg; end + #def ===(arg); @value === arg; end + end # class Cookie =================================================================== 続いて以下の問題に対するpatch (for 1.8.6 p.111) です。 [ruby-list:44321] で投稿したのと同じですが再送します。 * multipart時およびPOSTメソッド時に受信するデータのサイズを 確認していないため、巨大なデータを送信されるとサーバ資源が 食いつぶされる。 → Content-Lengthをチェックし、長過ぎれば例外を発生させる。 * multipart時に任意の数のparameterを受け付けるため、 例えば数千個のparameterを送信することで、サーバにたくさんの Tempfileオブジェクトを生成することができてしまう。 → parameterの数をチェックし、多すぎれば例外を発生させる。 簡単化のため制限値は定数で指定してますが、必要であればクラス変数や インスタンス変数で指定できるようにしてください。 Index: lib/cgi.rb =================================================================== --- lib/cgi.rb (revision 15382) +++ lib/cgi.rb (working copy) @@ -907,6 +907,17 @@ params end + + # Maximum content length of post data + MAX_CONTENT_LENGTH = 2 * 1024 * 1024 + + # Maximum content length of multipart data + MAX_MULTIPART_LENGTH = 128 * 1024 * 1024 + + # Maximum number of request parameters when multipart + MAX_MULTIPART_COUNT = 128 + + # Mixin module. It provides the follow functionality groups: # # 1. Access to CGI environment variables as methods. See @@ -984,7 +995,11 @@ raise EOFError, "bad content body" end + count = MAX_MULTIPART_COUNT loop do + unless (count -= 1) >= 0 + raise StandardError.new("too many parameters.") + end head = nil if 10240 < content_length require "tempfile" @@ -1106,7 +1121,11 @@ %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE']) boundary = $1.dup @multipart = true - @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) + content_length = Integer(env_table['CONTENT_LENGTH']) + unless content_length <= MAX_MULTIPART_LENGTH + raise StandardError.new("too large multipart data.") + end + @params = read_multipart(boundary, content_length) else @multipart = false @params = CGI::parse( @@ -1119,7 +1138,11 @@ end when "POST" stdinput.binmode if defined? stdinput.binmode - stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or '' + content_length = Integer(env_table['CONTENT_LENGTH']) + unless content_length <= MAX_CONTENT_LENGTH + raise StandardError.new("too large post data.") + end + stdinput.read(content_length) or '' else read_from_cmdline end =================================================================== また cgi.rb のテストスクリプトは、CGIAltに含まれています。 ([ruby-list:44331]に書いた通りです。) メールでお送りするには大きすぎると思うので、CGIAltをダウンロードして ご検討ください。 > cgi.rbの改善に私の言動はあまり関係ないと思いますけど。 まつもとさん個人に対してではなく、最近の世の中の風潮に対しての つもりでした。ご気分を害されたのでしたら申し訳ありません。 -- makoto kuwata