LoginSignup
396
394

More than 5 years have passed since last update.

今更聞けないSSL/HTTPS

Posted at

SSL/HTTPSの仕組みをざっくり理解しながら、
オレオレHTTPSの稼働まで。

0.そもそもSSLって何?

概要

SSLサーバー証明書とはウェブサイトの所有者の情報、送信情報の暗号化に必要な鍵、発行者の署名データを持った電子証明書です。

SSLサーバーには主に二つの役割があります。

  • 証明書に表示されたドメインの所有者であることの証明
  • ブラウザとウェブサーバー間でのSSL暗号化通信の実現

一般的には、第三者サービスがWHOISと企業実在情報を照会して証明書を発行します。証明書を発行する人を認証局といいます。

よし、SSLサーバー証明書をつくればいいんだな。

オレオレSSLとは

"俺自身が認証局になることだ…"

社会的信用はないSSLなので運用には注意してください。

その前に、暗号化ってなんですか?

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. 送信された情報をホスト側で受信してデコードします。

このときクライアントが勝手に暗号化するとホスト側でデコードができませんので、先にホストからクライアントに暗号化のルールを伝えます。

  1. ホストからクライアントに暗号化のルールを伝える
  2. クライアントが送る情報はクライアント側で暗号化して、
  3. 送信された情報をホスト側で受信してデコードします。

そのあたりを注目してRSAの動作を確認します。

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

うまくいきました。

396
394
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
396
394