[#31928] securerandom.rb for 1.8 — Tanaka Akira <akr@...>

securerandom.rb を 1.8 に追加し、cgi/session.rb に使わせたい

18 messages 2007/10/03
[#31990] Re: securerandom.rb for 1.8 — "Akinori MUSHA" <knu@...> 2007/10/09

At Wed, 3 Oct 2007 12:49:20 +0900,

[#31992] Re: securerandom.rb for 1.8 — Tanaka Akira <akr@...> 2007/10/09

In article <86k5pwinco.knu@iDaemons.org>,

[#31993] Re: securerandom.rb for 1.8 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/09

-----BEGIN PGP SIGNED MESSAGE-----

[#31936] Rake添付 — Yukihiro Matsumoto <matz@...>

まつもと ゆきひろです

21 messages 2007/10/04
[#31937] Re: Rake添付 — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/04

-----BEGIN PGP SIGNED MESSAGE-----

[#31938] Re: Rake添付 — Yukihiro Matsumoto <matz@...> 2007/10/04

まつもと ゆきひろです

[#31941] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — Shugo Maeda <shugo@...>

前田です。

20 messages 2007/10/04
[#31943] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/05

-----BEGIN PGP SIGNED MESSAGE-----

[#31945] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — Shugo Maeda <shugo@...> 2007/10/05

前田です。

[#31948] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/05

-----BEGIN PGP SIGNED MESSAGE-----

[#31952] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — Shugo Maeda <shugo@...> 2007/10/05

前田です。

[#31956] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — GOTOU Yuuzou <gotoyuzo@...> 2007/10/06

In message <47063403.3070402@ruby-lang.org>,

[#31960] Re: [ruby-list:44071] Re: Ruby 1.8.6-p111 / 1.8.5-p114 released (Security Fix) — GOTOU Yuuzou <gotoyuzo@...> 2007/10/07

In message <20071006.101915.596518898.gotoyuzo@sawara.priv.tokyo.netlab.jp>,

[#31980] multibyte string/regex literal with escape sequence — "U.Nakamura" <usa@...>

こんにちは、なかむら(う)です。

24 messages 2007/10/09
[#31981] Re: multibyte string/regex literal with escape sequence — Yukihiro Matsumoto <matz@...> 2007/10/09

まつもと ゆきひろです

[#31983] Re: multibyte string/regex literal with escape sequence — "U.Nakamura" <usa@...> 2007/10/09

こんにちは、なかむら(う)です。

[#31984] Re: multibyte string/regex literal with escape sequence — Yukihiro Matsumoto <matz@...> 2007/10/09

まつもと ゆきひろです

[#31986] Re: multibyte string/regex literal with escape sequence — "U.Nakamura" <usa@...> 2007/10/09

こんにちは、なかむら(う)です。

[#31987] Re: multibyte string/regex literal with escape sequence — Yukihiro Matsumoto <matz@...> 2007/10/09

まつもと ゆきひろです

[#32003] Re: multibyte string/regex literal with escape sequence — "U.Nakamura" <usa@...> 2007/10/10

こんにちは、なかむら(う)です。

[#32133] undefined method `now' for DateTime:Class (NoMethodError) — "NAKAMURA, Hiroshi" <nakahiro@...>

-----BEGIN PGP SIGNED MESSAGE-----

12 messages 2007/10/23
[#32135] Re: undefined method `now' for DateTime:Class (NoMethodError) — tadf@... 2007/10/23

どういう状況かよくわかってないのですが、いっそ必ず date 丸ごと読むようにするか、

[#32136] Re: undefined method `now' for DateTime:Class (NoMethodError) — "NAKAMURA, Hiroshi" <nakahiro@...> 2007/10/23

-----BEGIN PGP SIGNED MESSAGE-----

[ruby-dev:31928] securerandom.rb for 1.8

From: Tanaka Akira <akr@...>
Date: 2007-10-03 03:49:20 UTC
List: ruby-dev #31928
securerandom.rb を 1.8 に追加し、cgi/session.rb に使わせたい
のですが、どうでしょうか。

cgi/session.rb に限りませんが、session cookie の生成には暗号
学的にそれなりに安全な乱数が必要です。

しかし、現状の Ruby ではそのような安全な乱数を得る簡単な API
が用意されていないため、安全なんかどうなのかよくわからない怪
しげなコードで session cookie を生成することがあります。

やはり、そういう難しい暗号の話は、餅は餅屋ということで外部
(OpenSSL や /dev/urandom) にまかせるのがいいのではないでしょ
うか。

Index: lib/securerandom.rb
===================================================================
--- lib/securerandom.rb	(リビジョン 0)
+++ lib/securerandom.rb	(リビジョン 0)
@@ -0,0 +1,137 @@
+# = Secure random number generator interface.
+#
+# This library is an interface for secure random number generator which is
+# suitable for generating session key in HTTP cookies, etc.
+#
+# It supports following secure random number generators.
+#
+# * openssl
+# * /dev/urandom
+#
+# == Example
+#
+# # random hexadecimal string.
+# p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
+# p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
+# p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
+# p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
+# p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
+# ...
+#
+# # random base64 string.
+# p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
+# p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
+# p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
+# p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
+# p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
+# p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
+# ...
+#
+# # random binary string.
+# p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
+# p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
+# ...
+
+begin
+  require 'openssl'
+rescue LoadError
+end
+
+module SecureRandom
+  # SecureRandom.random_bytes generates a random binary string.
+  #
+  # The argument n specifies the length of the result string.
+  #
+  # If n is not specified, 16 is assumed.
+  # It may be larger in future.
+  #
+  # If secure random number generator is not available,
+  # NotImplementedError is raised.
+  def self.random_bytes(n=nil)
+    n ||= 16
+    if defined? OpenSSL::Random
+      return OpenSSL::Random.random_bytes(n)
+    end
+    if !defined?(@has_urandom) || @has_urandom
+      @has_urandom = false
+      flags = File::RDONLY
+      flags |= File::NONBLOCK if defined? File::NONBLOCK
+      flags |= File::NOCTTY if defined? File::NOCTTY
+      flags |= File::NOFOLLOW if defined? File::NOFOLLOW
+      begin
+        File.open("/dev/urandom", flags) {|f|
+          unless f.stat.chardev?
+            raise Errno::ENOENT
+          end
+          @has_urandom = true
+          ret = f.readpartial(n)
+          if ret.length != n
+            raise NotImplementedError, "Unexpected partial read from random device"
+          end
+          return ret
+        }
+      rescue Errno::ENOENT
+        raise NotImplementedError, "No random device"
+      end
+    end
+    raise NotImplementedError, "No random device"
+  end
+
+  # SecureRandom.hex generates a random hex string.
+  #
+  # The argument n specifies the length of the random length.
+  # The length of the result string is twice of n.
+  #
+  # If n is not specified, 16 is assumed.
+  # It may be larger in future.
+  #
+  # If secure random number generator is not available,
+  # NotImplementedError is raised.
+  def self.hex(n=nil)
+    random_bytes(n).unpack("H*")[0]
+  end
+
+  # SecureRandom.base64 generates a random base64 string.
+  #
+  # The argument n specifies the length of the random length.
+  # The length of the result string is about 4/3 of n.
+  #
+  # If n is not specified, 16 is assumed.
+  # It may be larger in future.
+  #
+  # If secure random number generator is not available,
+  # NotImplementedError is raised.
+  def self.base64(n=nil)
+    [random_bytes(n)].pack("m*").delete("\n")
+  end
+
+  # SecureRandom.random_number generates a random number.
+  #
+  # If an positive integer is given as n,
+  # SecureRandom.random_number returns an integer:
+  # 0 <= SecureRandom.random_number(n) < n.
+  #
+  # If 0 is given or an argument is not given,
+  # SecureRandom.random_number returns an float:
+  # 0.0 <= SecureRandom.random_number() < 1.0.
+  def self.random_number(n=0)
+    if 0 < n
+      hex = n.to_s(16)
+      hex = '0' + hex if (hex.length & 1) == 1
+      bin = [hex].pack("H*")
+      mask = bin[0]
+      mask |= mask >> 1
+      mask |= mask >> 2
+      mask |= mask >> 4
+      begin
+        rnd = SecureRandom.random_bytes(bin.length)
+        rnd[0] = (rnd[0] & mask).chr
+      end until rnd < bin
+      rnd.unpack("H*")[0].hex
+    else
+      # assumption: Float::MANT_DIG <= 64
+      i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
+      Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
+    end
+  end
+end
Index: lib/cgi/session.rb
===================================================================
--- lib/cgi/session.rb	(リビジョン 13603)
+++ lib/cgi/session.rb	(作業コピー)
@@ -174,16 +174,22 @@
     # is used internally for automatically generated
     # session ids. 
     def create_new_id
-      require 'digest/md5'
-      md5 = Digest::MD5::new
-      now = Time::now
-      md5.update(now.to_s)
-      md5.update(String(now.usec))
-      md5.update(String(rand(0)))
-      md5.update(String($$))
-      md5.update('foobar')
+      require 'securerandom'
+      begin
+        session_id = SecureRandom.hex(16)
+      rescue NotImplementedError
+        require 'digest/md5'
+        md5 = Digest::MD5::new
+        now = Time::now
+        md5.update(now.to_s)
+        md5.update(String(now.usec))
+        md5.update(String(rand(0)))
+        md5.update(String($$))
+        md5.update('foobar')
+        session_id = md5.hexdigest
+      end
       @new_session = true
-      md5.hexdigest
+      session_id
     end
     private :create_new_id
 
-- 
[田中 哲][たなか あきら][Tanaka Akira]

In This Thread

Prev Next