From: "TAKAGI, Hiromitsu" Date: 2001-12-29T10:31:25+09:00 Subject: [ruby-list:33104] Re: cgi.rb で cookie の encoding について もう少し考えてみました。エスケープ処理は結果オーライでやってしまうとセ キュリティ上の問題を引き起こすこともあるので、どのようにするのが最も正 しいかというのは興味あるところです。 On Sat, 29 Dec 2001 08:52:36 +0900 "TAKAGI, Hiromitsu" wrote: > つまり、cookieにprintableでない文字を入れる場合、それをescapeするのは、 > そのコードを書く者の責任であるとするのが正しいと思います。 そもそも、escapeメソッドを使用する目的には次の2種類があるようです。 (1) その文字列を、特定の文字を使用できない場所で使用するつもりの場合に、 その使用できない文字をescapeする。 具体的には、例えば日本語の文字列を、URLやcookieなどのnon-printable な文字を入れてはならないところに入れる場合がこれに該当します。 (2) その文字列を、特定の文字がメタキャラクタとなっている文脈で使用する 場合に、そのメタキャラクタと同じ文字をescapeする。 具体的には、その文字列を、ある区切り文字(例えば「&」)で連結して 使用する際に、区切り文字と同じ文字をescapeする。 これら2つの目的のために、同じescapeメソッドが使用されているわけですが (JavaScriptのescapeメソッドもそうなっている)、本来この2つの目的には 別々のメソッドを用意すべきではないでしょうか。すなわち、 (1)の目的のために: 使用できない文字だけをエスケープするメソッド。 例えばURLの場合、RFCの定義に従って該当する文字だけをエスケープする と、「&」などはエスケープされない。この点で、現状の escapeメソッド とは異なる処理。 (2)の目的のために: 引数に指定された文字だけをエスケープするメソッド。 例えば「&」で連結する場合には、 foo.cgi? + "aaa" + escpae("&", aaa_val) + "&" + "bbb" + escape(... のように、「escape("&", aaa_val)」と、その文脈におけるメタキャラク タを引数に指定する。 そして、これら(1)、(2)と直交して、どのようなエンコード方法でエスケープ するかがあるわけですね。で、URLおよびcookieの場合は URL encode(%XX) を使用することになっていると。 なので、 (1)のメソッドを例えば「url_normalize(source_string)」、 (2)のメソッドを例えば「url_escape(metacharacters, source_string)」 として準備しておき、 例えば cgi-lib.rb の def CGI::cookie(options) "Set-Cookie: " + options['name'] + '=' + escape(options['value']) + (options['domain'] ? '; domain=' + options['domain'] : '') + (options['path'] ? '; path=' + options['path'] : '') + (options['expires'] ? '; expires=' + rfc1123_date(options['expires']) : '') + (options['secure'] ? '; secure' : '') end は、次にようにするのが妥当ではないかと。 def CGI::cookie(options) "Set-Cookie: " + url_normalize( url_escape([':', ';', ' '], url_escape(['='], options['name']) + '=' + url_escape(['='], options['value']) ) + (options['domain'] ? '; ' + url_escape([':', ';', ' '], 'domain=' + url_escape(['='], options['domain']) ) : '' ) + (options['... ... ) end こうしておけば、valueに渡す文字列に事前にエスケープ処理は必要ないと。 それで、valueに複数のものを適当な区切り記号で連結して渡したいならば、 そういうデータ構造のためのクラスを用意して処理するのが良いのではないか と。例えば、 value = concatenated_values.new('|', p1, p2, p3) として使用すると。(もしp1内に「|」が含まれているならエスケープされる) 高木 浩光@独立行政法人産業技術総合研究所 http://staff.aist.go.jp/takagi.hiromitsu/