[ruby-trunk - Bug #8995][Open] バイナリデータを文字列として encode! すると readbyte の結果が変化する

Issue #8995 has been reported by hsbt (Hiroshi SHIBATA).


Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by nobu (Nobuyoshi N.).

最小コードはこんな感じですね。
$ ruby -E:UTF-8 -e ‘p “\xff”.encode.unpack(“C*”)’
[239, 191, 189]
Encoding.default_internalをセットしていると、同じエンコーディング同士でも変換が起きているようです。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by nobu (Nobuyoshi N.).

Description updated

理由はr40390です。

* transcode.c (str_transcode0): If invalid: :replace is specified 

for
String#encode, replace invalid byte sequence even if the
destination
encoding equals to the source encoding.

encode_paramsの引数はHTTPで渡ってくるパラメータのようですから、バイナリデータかどうかを判断する手がかりが他にあればともかく、valid_encodingでなければASCII-8BITにするくらいしかできないんじゃないでしょうか。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

((<encode_params|URL:rails/actionpack/lib/action_dispatch/http/parameters.rb at 3-2-stable · rails/rails · GitHub>))

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by nobu (Nobuyoshi N.).

Status changed from Open to Third Party’s Issue

まぁ、そもそもバイナリデータをエンコーディング変換したら壊れるのが当然ですね。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Third Party’s Issue
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

((<encode_params|URL:rails/actionpack/lib/action_dispatch/http/parameters.rb at 3-2-stable · rails/rails · GitHub>))

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by hsbt (Hiroshi SHIBATA).

Category set to core
Target version set to current: 2.1.0


Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by nobu (Nobuyoshi N.).

同じエンコーディング間では何もしていなかったので、防御にはなっていなかったんじゃないでしょうか。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Third Party’s Issue
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

((<encode_params|URL:rails/actionpack/lib/action_dispatch/http/parameters.rb at 3-2-stable · rails/rails · GitHub>))

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by hsbt (Hiroshi SHIBATA).

rails の該当箇所は rails 3 リリース時から存在するもので、invalid な utf-8
をパラメータとして渡して攻撃するものを防御するためのコードのようです。いったん、rails 側で何とかできないか考えてきます。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Third Party’s Issue
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

((<encode_params|URL:rails/actionpack/lib/action_dispatch/http/parameters.rb at 3-2-stable · rails/rails · GitHub>))

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by nobu (Nobuyoshi N.).

workaroundが入ったようですが、元々UTF-8ではないバイナリデータが壊れないということは、裏を返せばmalformed
UTF-8の攻撃文字列も破棄されないということです。
つまり、脆弱性はそのまま残っているわけなので、何らかの対策が必要であろうことだけは警告しておきます。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Third Party’s Issue
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

((<encode_params|URL:rails/actionpack/lib/action_dispatch/http/parameters.rb at 3-2-stable · rails/rails · GitHub>))

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end

Issue #8995 has been updated by naruse (Yui NARUSE).

なかださんの指摘の通り、

return params.force_encoding(“UTF-8”).encode!
の行は何がしたいのかよくわかりませんね。
本当は
return params.force_encoding(“UTF-16”).encode!
とやって、まさに Ruby 2.1 の挙動にしたかったのかな。

結論もなかださんの仰るとおり、
バイナリデータフラグを加えるか、ASCII-8BITで流すかあたりになるんじゃないかと思います。

Bug #8995: バイナリデータを文字列として encode! すると readbyte の結果が変化する

Author: hsbt (Hiroshi SHIBATA)
Status: Third Party’s Issue
Priority: Normal
Assignee:
Category: core
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
Rails の以下のコードの結果が 2.0 と 2.1 とで異なるようです。

((<encode_params|URL:rails/actionpack/lib/action_dispatch/http/parameters.rb at 3-2-stable · rails/rails · GitHub>))

以下が最小ケースです。

$ ruby -v
=> ruby 2.1.0dev (2013-10-07 trunk 43160) [x86_64-darwin12.5.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 239

なお、2.0 ではそれぞれの値が変化しませんでした。

$ ruby -v
=> ruby 2.0.0p326 (2013-10-05 revision 43144) [x86_64-darwin13.0.0]
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’)).readbyte”
=> 255
$ ruby -rstringio -e “Encoding.default_internal = Encoding::UTF_8; p
StringIO.new(File.read(‘x.jpg’).force_encoding(‘UTF-8’).encode!).readbyte”
=> 255

rails の該当箇所は rails4 でも同じ処理を行っているので、このままだと post で画像などを送るともれなく壊れてしまいます。

rails のコードがよくないのか、File.binread を使って読み込んでないのがおかしいなど教えて頂けると嬉しいです。

=end