1. mosson

    Posted

    mosson
Changes in title
+今更聞けないSSL/HTTPS
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,264 @@
+
+SSL/HTTPSの仕組みをざっくり理解しながら、
+オレオレHTTPSの稼働まで。
+
+##0.そもそもSSLって何?
+
+###概要
+
+SSLサーバー証明書とはウェブサイトの所有者の情報、送信情報の暗号化に必要な鍵、発行者の署名データを持った電子証明書です。
+
+SSLサーバーには主に二つの役割があります。
+
+- 証明書に表示されたドメインの所有者であることの証明
+- ブラウザとウェブサーバー間でのSSL暗号化通信の実現
+
+一般的には、第三者サービスがWHOISと企業実在情報を照会して証明書を発行します。証明書を発行する人を認証局といいます。
+
+よし、SSLサーバー証明書をつくればいいんだな。
+
+###オレオレSSLとは
+
+"俺自身が認証局になることだ…"
+
+社会的信用はないSSLなので運用には注意してください。
+
+###その前に、暗号化ってなんですか?
+
+```ruby:sample_cipher.rb
+# encoding: utf-8
+
+require 'OpenSSL'
+
+def encrypt_data(data, password, salt)
+ #暗号化方式を選ぶ
+ cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
+ cipher.encrypt
+ cipher.pkcs5_keyivgen(password, salt)
+ cipher.update(data) + cipher.final
+end
+
+def decode_data(data, password, salt)
+ cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
+ cipher.decrypt
+ cipher.pkcs5_keyivgen(password, salt)
+ cipher.update(data) + cipher.final
+end
+
+password = "foobar" # pass_phrase
+salt = "8-octets" # 8-octet string
+
+data = "Hello, World" # このデータを暗号化するとします
+
+# 暗号化
+encrypted_data = encrypt_data(data, password, salt)
+p encrypted_data
+# => "\xDEW\xFD\x8A\xB6\x83\xF1\xC1\x96\x15\x81\x02\xE3\x05\x879"
+
+# 復号化
+p decode_data( encrypted_data, password, salt )
+# => "Hello, World"
+```
+
+パスフレーズとソルトを使って暗号化・復号化しています。
+
+####塩?
+
+ソルトって何という疑問が浮かぶと思います。
+平たくいえば、パスフレーズをランダム化するために使います。
+
+例えばいまパスワードは"foobar"ですが、データ流出事故が起きたとします。
+
+- DBのpasswordの項目に"foobar"と入っている場合
+言わずもがなパスワードも流出します
+
+- DBのpasswordの項目に"foobar"を暗号化したもの"x83\xF1\xC1\x96\x15\x81\"が入っている場合
+"x83\xF1\xC1\x96\x15\x81\"が出るまでpass_phraseを入れ続けて一致すれば、元のpasswordが"foobar"が判明する
+
+- DBのpasswordの項目はその時々にソルトを使って暗号化される場合
+"x83\xF1\xC1\x96\x15\x81\"に一致するパスフレーズが見つかったとしても"foobar"は判明しない
+ソルトがわかっていたら?となるので、"foobar"をパスワードとしているユーザーが複数いたらそれぞれにソルトを変える
+
+故にソルトは一意に生成されます
+そしてソルトの長さは上の例では8-octet stringでしたが、暗号化方式によってまちまちです。
+
+とりあえずこれだけでも秘密のトークアプリケーションがつくれますね。
+
+####RSA?
+
+暗号化と証明書を同時につくれるナイスな方式がRSAです。
+誰が暗号化するのか、誰が復号化するのかを考えると、
+
+1. クライアントが送る情報はクライアント側で暗号化して、
+2. 送信された情報をホスト側で受信してデコードします。
+
+このときクライアントが勝手に暗号化するとホスト側でデコードができませんので、先にホストからクライアントに暗号化のルールを伝えます。
+
+0. ホストからクライアントに暗号化のルールを伝える
+1. クライアントが送る情報はクライアント側で暗号化して、
+2. 送信された情報をホスト側で受信してデコードします。
+
+そのあたりを注目してRSAの動作を確認します。
+
+```ruby:sample_rsa.rb
+# encoding: utf-8
+
+require 'openssl'
+include OpenSSL::PKey
+
+### 1.SSL証明書を発行
+
+# RSAを鍵長2048bitで作成します
+rsa = RSA.generate(2048)
+
+# 公開鍵を取得します
+public_key = rsa.public_key.to_s
+
+# 暗号鍵を取得します 暗号化にパスワードを入力します ここでは'password'にしてます
+private_key = rsa.export(OpenSSL::Cipher::Cipher.new('aes256'),'password')
+
+### 2.クライアント側の処理を想定
+# 公開鍵をもらいます
+
+# 発行された公開鍵でRSAを作成します
+pub = RSA.new(public_key)
+
+# 送信する情報の暗号化
+enc_data = pub.public_encrypt("Personal Information")
+
+p enc_data #=> 暗号化されたデータ よくわからない文字列
+
+### 3.ホスト側の処理を想定
+# 送信された情報を受信した!
+
+# 暗号鍵でRSAを作成します 暗号化されているのでパスワードも必要です
+private = RSA.new(private_key,'password')
+
+# 送信された情報を復号化します
+p private.private_decrypt(enc_data) #=> 'Personal Information' 復号化できました
+```
+
+できました。
+前段が長くなりましたが、いよいよ本番です。
+
+
+##1.DES3という暗号化方式でRSA暗号鍵を"server.key"という名前で生成
+
+暗号鍵のパスフレーズを設定します
+
+```
+$ [sudo] openssl genrsa -des3 -out server.key 1024
+
+Enter pass phrase for server.key:
+Verifying - Enter pass phrase for server.key:
+
+# genrsa Generation of RSA Private Key. Superceded by genpkey.
+# 暗号化方式一覧
+# Cipher commands (see the `enc' command for more details)
+# aes-128-cbc aes-128-ecb aes-192-cbc # aes-192-ecb
+# aes-256-cbc aes-256-ecb base64 # bf
+# bf-cbc bf-cfb bf-ecb bf-ofb
+# camellia-128-cbc camellia-128-ecb camellia-192-cbc camellia-192-ecb
+# camellia-256-cbc camellia-256-ecb cast cast-cbc
+# cast5-cbc cast5-cfb cast5-ecb cast5-ofb
+# des des-cbc des-cfb des-ecb
+# des-ede des-ede-cbc des-ede-cfb des-ede-ofb
+# des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb
+# des-ofb des3 desx rc2
+# rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb
+# rc2-ecb rc2-ofb rc4 rc4-40
+# seed seed-cbc seed-cfb seed-ecb
+# seed-ofb zlib
+
+```
+
+##2.RSA暗号鍵から"server.csr"という名前で証明書を発行
+
+証明書に必要な情報をいろいろ聞かれます。
+
+```
+$ [sudo] openssl req -new -key server.key -out server.csr
+
+Enter pass phrase for server.key: [暗号鍵のパスワード]
+
+Country Name (2 letter code) [XX]:
+State or Province Name (full name) []:
+Locality Name (eg, city) [Default City]:
+Organization Name (eg, company) [Default Company Ltd]:
+Organizational Unit Name (eg, section) []:
+Common Name (eg, your name or your server's hostname) []:
+Email Address []:
+
+Please enter the following 'extra' attributes
+to be sent with your certificate request
+A challenge password []:
+An optional company name []:
+```
+
+
+##3.毎回のパスワード入力を避けるため暗号鍵を復号化
+
+```
+$ [sudo] cp server.key server.key.org
+$ [sudo] openssl rsa -in server.key.org -out server.key
+Enter pass phrase for server.key.org:
+writing RSA key
+
+# openssl rsa [-in filename] : ファイルをRSA復号
+#
+# -in filename
+# 入力する証明書要求のファイル名(filename)
+# デフォルトは、標準出力
+# -out filename
+# 出力する証明書要求のファイル名(filename)
+# デフォルトは、標準出力
+```
+
+##4.SSL証明書の作成
+
+とりあえず30日の期限にします。
+
+```
+$ openssl x509 -req -days 30 -in server.csr -signkey server.key -out server.crt
+
+# 形式
+# openssl req [-new] [-in filename] [-out filename] # [-key filename]
+# [-x509] [-days n]
+# 機能
+# 証明書の署名要求(CSR)の作成
+# オプション
+# -in filename
+# 入力する証明書要求のファイル名(filename)
+# デフォルトは、標準出力
+# -out filename
+# 出力する証明書要求のファイル名(filename)
+# デフォルトは、標準出力
+# -signkey filename
+# 入力する秘密鍵のファイル名(filename)
+# -days n
+# X.509形式の証明書の有効期限をn日とする
+```
+
+以上でオレオレSSL証明書が発行できました。
+
+
+##(5.nginxで動作させてみる)
+
+nginxのconfに書いてみる
+
+```
+server {
+ :
+ listen 443 default ssl;
+ ssl on;
+ ssl_certificate /path/to/server.crt;
+ ssl_certificate_key /path/to/server.key;
+ :
+}
+```
+
+サーバーを再起動させてアクセスすると、
+
+![ssl](https://raw.github.com/mosson/mosson/master/imgs/ssl.png)
+
+うまくいきました。