開発環境でSSLを使うために、Webrick SSLをポート443で立ち上げる(Windows XP)

httpsでしか、アクセスできないページを作成しようと、ssl_requirement を使おうと思ったのだが、ローカルでSSL環境を作らないといけない。


そこで、WebrickSSLをポート443で立ち上げようとしてみたら、

C:\rails_app>ruby script/webrick_ssl -p 443
=> Booting WEBrick on SSL...
=> Rails application started on http://0.0.0.0:443
=> Ctrl-C to shutdown server; call with --help for options
Enter PEM pass phrase:
[2007-10-17 10:46:11] INFO  WEBrick 1.3.1
[2007-10-17 10:46:11] INFO  ruby 1.8.6 (2007-03-13) [i386-mswin32]
[2007-10-17 10:46:11] WARN  TCPServer Error: Bad file descriptor - bind(2)
c:/ruby/lib/ruby/1.8/webrick/utils.rb:73:in `initialize': Bad file descriptor - bind(2) (Errno::EBADF)
        from c:/ruby/lib/ruby/1.8/webrick/utils.rb:73:in `new'
        from c:/ruby/lib/ruby/1.8/webrick/utils.rb:73:in `create_listeners'
        from c:/ruby/lib/ruby/1.8/webrick/utils.rb:70:in `each'
        from c:/ruby/lib/ruby/1.8/webrick/utils.rb:70:in `create_listeners'
        from c:/ruby/lib/ruby/1.8/webrick/ssl.rb:87:in `listen'
        from c:/ruby/lib/ruby/1.8/webrick/server.rb:63:in `initialize'
        from c:/ruby/lib/ruby/1.8/webrick/httpserver.rb:24:in `initialize'
        from script/webrick_ssl:136:in `new'
        from script/webrick_ssl:136:in `dispatch'
        from script/webrick_ssl:145

ポートを変えると動くので、どうもWindowsでポート443が使われているらしい。


それで、だれがポートを利用しているのか、「PortReporter」というソフトがあったので、調べてみた。

結果・・・

4076:firefox.exe	TCP 443  	0.0.0.0 	LISTENING	 0.0.0.0

FireFoxであることが判明!!

FireFoxを落としたらWebrick SSLは443で立ち上がってくれました。

なぜFireFoxは443を占領するのか・・・は調べませんでした・・・。



ssl_requirement
http://dev.rubyonrails.org/svn/rails/plugins/ssl_requirement/
ssl_requirement を改造して、https => http の画面遷移でブラウザの警告をなくす - elm200 の日記
Webrick SSL
SSL 上で WEBrick を動かす - elm200 の日記
○PortReporter
@IT:Windows TIPS -- Tips:Port ReporterツールでTCP/IPの通信状態を調査する

テストWebサーバー(WEBrick)準備(ベリサインSSL導入)

★★今回やりたいこと★★
テストサーバーにベリサインSSLhttp://www.verisign.co.jp/)を導入したい。
Webサーバーは「WEBrick」とする。

VeriSign Class 3 Primary CA
VeriSign Class 3 Primary CA G2
VeriSign/RSA Secure Server CA

上記の3つのどれかが良い。


★★ベリサインSSLを導入する目的★★
1.「暗号化通信」をすることで、ネットワークを流れる個人情報の漏えいを防ぐ。
2.「運営している組織が本物である」ということを確認できる。
3.携帯電話端末にインストールされているルート証明書ベリサインが多いため。(http://triaez.kaisei.org/~kaoru/ssl/cell.html)

テストサーバーにベリサインを導入する理由は3の影響が大きい。


★★無料テストIDでテストしてみる★★
https://digitalid.verisign.co.jp/trialserver/trialIntro.htm

以下5つのステップを踏む

Step 1: CSRの生成
Step 2: CSRの提出
Step 3: 申請フォームの入力
Step 4: テスト用ルート証明書のインストール
Step 5: テスト用セキュア・サーバIDのインストール

○Step 1: CSRの生成
CSRとは、認証局に提出する署名リクエスト(Certificate Signing Request)です。
https://digitalid.verisign.co.jp/trialserver/trialStep1.htm
↑OpenSSLを利用する場合はこれでよさそう。
※今回利用するマシンは、/usr/bin/openssl にOpenSSLがインスコされていた。

CSRの生成例

# cd /usr/bin
# ./openssl md5 * > rand.dat
# ls -la | grep rand.dat
-rw-r--r--  1 root root     131748  9月 12 12:29 rand.dat
# openssl genrsa -rand rand.dat -des3 1024 > 2007key.pem
131748 semi-random bytes loaded
Generating RSA private key, 1024 bit long modulus
............++++++
...................................++++++
e is 65537 (0x10001)
Enter pass phrase:(パスワード入力。忘れないようにする)
Verifying - Enter pass phrase:(パスワード入力。忘れないようにする)
# ls -la | grep 2007key
-rw-r--r--  1 root root        963  9月 12 12:32 2007key.pem
# openssl req -new -key 2007key.pem -out 2007csr.pem
Country Name (2 letter code) [GB]:JP
State or Province Name (full name) [Berkshire]:(都道府県:例 Tokyo)
Locality Name (eg, city) [Newbury]:(市区町村:例 Minato)
Organization Name (eg, company) [My Company Ltd]:(会社名)
Organizational Unit Name (eg, section) []:(部署名)
Common Name (eg, your name or your server's hostname) []:(SSL接続の際のURL:FQDN)
Email Address []:(何も入力なし)
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:(何も入力なし)
An optional company name []:(何も入力なし)
[root@localhost bin]# cat 2007csr.pem
-----BEGIN CERTIFICATE REQUEST-----
MIIBwjCCASsCAQAwgYExCzAJBgNVBAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEPMA0G
A1UEBxMGTWluYXRvMSMwIQYDVQQKDBpMaXZlIFJldm9sdXRpb24gQ28uLEtMCAh0
ZDEOMAwGA1UECxMFYXJpZXMxHDAaBgNVBAMTE2ZrdXNoaWcubGVpYWEuanAuanAw
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6nj5rVgw3eVvpqRUWMe9WA+awY
UW2ptPvR7tppRlRH3IjO6GrIiNoGjuljWtdymlHWwTYJRSFK339/hNjK3VBTU+yC
7YZKJduMxLoqWFPQHzkzgMWEHiJmPqBGbaMDr7s7YLOW3liwcB16/nRywv6T79et
Z6TIrHW3VARGEY0LAgMBAAGgADANBgkqhkiG9w0BAQUFAAOBgQClgcgSgCRhKJRB
026Guy3SfBf+a1s292dj3FCekIQ7MzU3yomYlw5ZWGtvx/UBXk5sOXFFI0sBwoJ4
C5l09x7wACm8GEOfmzJJw+UtOqMcV+cF7QHMS3fY0mYr3LysxhGxEhuh29jS5klp
eiFpilEx3oBr57wQviP9muc/FS6Hjg==
-----END CERTIFICATE REQUEST-----

2007csr.pem => これはベリサインに申請するためのもの
2007key.pem => これは秘密鍵。大事に大事にしましょう。

※ハマリどころ

# ./openssl md5 * > rand.dat
Read Error in X11
18247:error:0200B015:system library:fread:Is a directory:bss_file.c:167:
18247:error:20082002:BIO routines:FILE_READ:system lib:bss_file.c:168:
[root@live-passport bin]# ls -la | grep rand.dat
-rw-r--r-- 1 root root      52967 Sep 12 12:43 rand.dat

↑というエラー。でも、rand.datは生成される。
「OpenSSLの擬似乱数情報の生成について」(1) Linux Square − @IT
↑「推奨はできないが、問題ない」という話。


○Step 2: CSRの提出
https://digitalid.verisign.co.jp/trialserver/trialStep2ns.htm

Step 1で生成した 2007csr.pemの中身をコピーしてフォームに入力する。

○Step 3: 申請フォームの入力
指示に従いフォームを入力していく。
※入力が終わると、ベリサイン発行の公開鍵をゲットできる。

○Step 4: テスト用ルート証明書のインストール
申し込み後にくるメールにもURLが書かれていて、そこからでも取得できます。

○Step 5: テスト用セキュア・サーバIDのインストール
Webサーバーにより異なります。

★★方法★★
WEBrick SSL - 基本へ帰ろう
↑こちらをみて、ベリサインからゲットした公開鍵と初めに生成した秘密鍵をセットすればOK!

WEBrick SSL

2007-04-28 - elm200 の日記
http://lists.rubyonrails.org/pipermail/rails/2006-January/012432.html
↑参考

1.サーバ証明書作成

#!/usr/bin/env ruby
require 'webrick/ssl'
# cn と comment を適当に設定
cn = [ [ "CN", "server_name" ] ]  
comment = "Generated by Ruby/OpenSSL"   
cert, rsa = WEBrick::Utils::create_self_signed_cert(1024, cn, comment)
puts cert.to_s
puts rsa.to_s

↑こちらを実行する。

2.以下のソース(名前は webrick_ssl とする)をrailsプロジェクト(/script/webrick_ssl)に設置

#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'

require 'active_support'
require 'fileutils'

puts "=> Booting WEBrick on SSL..."

%w(cache pids sessions sockets).each { |dir_to_make| FileUtils.mkdir_p(File.join(RAILS_ROOT, 'tmp', dir_to_make)) }

require 'webrick'
require 'webrick/https'
require 'optparse'

OPTIONS = {
  :port            => 3500,
  :ip              => "0.0.0.0",
  :environment     => (ENV['RAILS_ENV'] || "development").dup,
  :server_root     => File.expand_path(RAILS_ROOT + "/public/"),
  :server_type     => WEBrick::SimpleServer,
  :charset         => "UTF-8",
  :mime_types      => WEBrick::HTTPUtils::DefaultMimeTypes
}

ARGV.options do |opts|
  script_name = File.basename($0)
  opts.banner = "Usage: ruby #{script_name} [options]"

  opts.separator ""

  opts.on("-p", "--port=port", Integer,
          "Runs Rails on the specified port.",
          "Default: 3000") { |v| OPTIONS[:port] = v }
  opts.on("-b", "--binding=ip", String,
          "Binds Rails to the specified ip.",
          "Default: 0.0.0.0") { |v| OPTIONS[:ip] = v }
  opts.on("-e", "--environment=name", String,
          "Specifies the environment to run this server under (test/development/production).",
          "Default: development") { |v| OPTIONS[:environment] = v }
  opts.on("-m", "--mime-types=filename", String,
                  "Specifies an Apache style mime.types configuration file to be used for mime types",
                  "Default: none") { |mime_types_file| OPTIONS[:mime_types] = WEBrick::HTTPUtils::load_mime_types(mime_types_file) }

  opts.on("-d", "--daemon",
          "Make Rails run as a Daemon (only works if fork is available -- meaning on *nix)."
          ) { OPTIONS[:server_type] = WEBrick::Daemon }

  opts.on("-c", "--charset=charset", String,
          "Set default charset for output.",
          "Default: UTF-8") { |v| OPTIONS[:charset] = v }

  opts.separator ""

  opts.on("-h", "--help",
          "Show this help message.") { puts opts; exit }

  opts.parse!
end

ENV["RAILS_ENV"] = OPTIONS[:environment]
RAILS_ENV.replace(OPTIONS[:environment]) if defined?(RAILS_ENV)

require RAILS_ROOT + "/config/environment"
require 'webrick_server'

OPTIONS['working_directory'] = File.expand_path(RAILS_ROOT)

puts "=> Rails application started on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
puts "=> Ctrl-C to shutdown server; call with --help for options" if OPTIONS[:server_type] == WEBrick::SimpleServer

class DispatchServlet
  def self.dispatch(options = {})
  
      ssl_certificate =<<-EOS
-----BEGIN CERTIFICATE-----
MIICSjCCAbOgAwIBAwIBADANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDDAVmdW5r
eTAeFw0wNzA0MjgwNzA5NDdaFw0wODA0MjcwNzA5NDdaMBAxDjAMBgNVBAMMBWZ1
bmt5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDj1KnSH9E34aKFbIbRdL/d
ZSK6u+kTKPq4ZXGuxuvY0qP7geye/uCRZqdJWq4uwja/PiMpT/Hvz4xSydW94Cxi
x3Km6e2Yg1CbcAaj8ctT2BVaMpVXDXtw5z7/OGyokRllSCQWLkvoKzmZTcwNkA3L
QhzcroXybmkP20URQcrT2wIDAQABo4GzMIGwMAkGA1UdEwQCMAAwCwYDVR0PBAQD
AgUgMB0GA1UdDgQWBBRwbDNU99ejg8VFZC0FL5NwG5dx7DATBgNVHSUEDDAKBggr
BgEFBQcDATAoBglghkgBhvhCAQ0EGxYZR2VuZXJhdGVkIGJ5IFJ1YnkvT3BlblNT
TDA4BgNVHSMEMTAvgBRwbDNU99ejg8VFZC0FL5NwG5dx7KEUpBIwEDEOMAwGA1UE
AwwFZnVua3mCAQAwDQYJKoZIhvcNAQEFBQADgYEAP+isplcC6AOHpZK3bf58kELP
t89+xLP0x0BUGpMW4vQPwsG898VCLQ5NstwOc/dewGh4NWPyy7LUQe1wF6QWjIf/
wJO2ZoH+vKi3fu+nmG/xbyl056PRvqsyWwe+1O5JWe1JQ/Zhna0cDZhoYpUdE1/l
Gr3R7knmq+CfxH+dGmk=
-----END CERTIFICATE-----
      EOS

      ssl_private_key =<<-EOS
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDj1KnSH9E34aKFbIbRdL/dZSK6u+kTKPq4ZXGuxuvY0qP7geye
/uCRZqdJWq4uwja/PiMpT/Hvz4xSydW94Cxix3Km6e2Yg1CbcAaj8ctT2BVaMpVX
DXtw5z7/OGyokRllSCQWLkvoKzmZTcwNkA3LQhzcroXybmkP20URQcrT2wIDAQAB
AoGASRj7X4qL0vUW8t4OJ3fg80S2rtkJf/c+8hjCL8Rs+UUkDdbyt1Spcp1QAQ4S
Irh3Xkaue1vGER4zNIDDjkc1leSvBMqfS3WAjZGoEXHmhGpwhZsQQ1tdN8l3iYYx
r4orcnWB3f1Amle7TKoufKDrILZwOicJ0ov2UkjKp+0k+1ECQQD8V3tm7VPOUbqW
cJMWgT/Mle3QAnjS72gNCtEOdXmqQwMYwJyFZDcfeD9WYOsZVoCpzgo/+fCvna36
1r7uNs9zAkEA5yI2obeST9KcG7yGXk2XzSa3kdNm1bIqDpNyy/LzGcoK8/vQECPs
5K2vLBW+I2T7XdIeygElVb1RQbVglet/+QJBAKFRqAFYDbCjjR5p346OmGPJIZxO
SEHJbYKQ/K86qMoRRySG1klslNTYgd1N3l53b4+euezGc3lB25y1tqABiEMCQQDP
LDyZ0chkohvpRJ+QMa6qZVTPchTP4OWPsRyJsJe0ewQ8U27YuMri4seMFWUbpq0l
GG0elc5YPtxxsFkFqFRJAkAXaY3hnkwmj7/+Bhg1JG5t0B1NURKdj79gpS3DV8y6
pXtjPCIm3f2Rlnc6Pc5ECNV9vfBt+Ij/7g52zGyQYEkU
-----END RSA PRIVATE KEY-----
      EOS

      Socket.do_not_reverse_lookup = true # patch for OS X

      params = { :Port        => options[:port].to_i,
                 :ServerType  => options[:server_type],
                 :BindAddress => options[:ip],
                 :SSLEnable        => true,
                 :SSLCertificate => OpenSSL::X509::Certificate.new(ssl_certificate),
                 :SSLPrivateKey  => OpenSSL::PKey::RSA.new(ssl_private_key)
               }
      params[:MimeTypes] = options[:mime_types] if options[:mime_types]

      server = WEBrick::HTTPServer.new(params)
      server.mount('/', DispatchServlet, options)

      trap("INT") { server.shutdown }
      
      server.start
  end
end

DispatchServlet.dispatch(OPTIONS)

3.起動する

[root@lv8195 /]# ruby script/webrick_ssl

もちろん、

[root@lv8195 /]# ruby script/webrick_ssl -d -p 443

でもOK.


※試したマシン

[root@lv8195 /]# less /etc/redhat-release 
Red Hat Enterprise Linux ES release 4 (Nahant Update 4)


RubyƒŠƒtƒ@ƒŒƒ“ƒXƒ}ƒjƒ ƒAƒ‹