クライアント証明書を利用したHTTPS通信をやってみました。
準備
まずは、オレオレ認証局を立てて、サーバ証明書とクライアント証明書を発行します。
ここがとても参考になりました。
→ https://qiita.com/k-masaki/items/12b5e8a1874214308912
セキュリティーの関係でちょっと変わったところがあったので、その点を記録しておきます。
SHA1 → SHA256 に変更
OpenSSL::Cipher::Cipher.new('aes256') → OpenSSL::Cipher.new("AES-256-CBC")
くらいですか。最後のはまあおまけみたいなものですが。。。
各証明書ができたらサーバに設定します。
今回は nginx に設定します。
→ https://qiita.com/tukiyo3/items/71245d7263fed3601ebd
server {
listen 443 ssl;
ssl_certificate /domain.crt;
ssl_certificate_key /domain.key;
ssl_verify_client on;
ssl_client_certificate /ca.pem;
}
そしたら再起動。$ /etc/init.d/nginx stop
$ /etc/init.d/nginx start
クライアント証明書のインストール
client.pfx
をダブルクリックすると、クライアント証明証のパスワードを聞いてくるので、入力します。するとキーチェーンアクセスが起動するので、「ログイン」のところにインストールします。
で、safari でアクセス!
いろいろ聞いてきますが、適宜対応します(^^
表示されればOKです。
Rubyでアクセス!
# -*- coding: utf-8 -*-
require "json"
require "openssl"
require "net/http"
require "uri"
require "cgi"
class ClientCertTest
attr_accessor :use_client_cert
def initialize
@use_client_cert = false
@client_pass = "password"
end
# --------------------------------------------------------------------------
def request_post(postdata, endpoint, htmlret = false)
uri = URI.parse(endpoint)
response = nil
begin
if endpoint =~ /^https/
https = Net::HTTP.new(uri.host, 443)
https.use_ssl = true
if @use_client_cert
pkcs = OpenSSL::PKCS12.new(File.read("client.pfx"), @client_pass)
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.ca_file = "ca.pem"
https.key = pkcs.key
https.cert = pkcs.certificate
else
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
https.start{|h|
request = Net::HTTP::Post.new(uri.path)
request.set_form_data(postdata)
response = h.request(request)
}
else
Net::HTTP.start(uri.host, uri.port){|http|
request = Net::HTTP::Post.new(uri.path)
request.set_form_data(postdata)
response = http.request(request)
}
end
p response.code
jsondata = response.body.strip
errflg = false
errflg = true if htmlret == false && jsondata =~ /^<html>/
if errflg
raise ClientCertTestError.new(jsondata.force_encoding("utf-8"))
end
rescue
jsondata = nil
end
return jsondata
end
# --------------------------------------------------------------------------
def request_get(getdata, endpoint, htmlret = false)
dparams = URI.encode_www_form(getdata)
uri = URI.parse(endpoint + "?" + dparams)
response = nil
begin
if endpoint =~ /^https/
https = Net::HTTP.new(uri.host, 443)
https.use_ssl = true
if @use_client_cert
pkcs = OpenSSL::PKCS12.new(File.read("client.pfx"), @client_pass)
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.ca_file = "ca.pem"
https.key = pkcs.key
https.cert = pkcs.certificate
else
https.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
https.start{|h|
request = Net::HTTP::Get.new(uri.request_uri)
response = h.request(request)
}
else
Net::HTTP.start(uri.host, uri.port){|http|
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
}
end
jsondata = response.body.strip
errflg = false
errflg = true if htmlret == false && jsondata =~ /^<html>/
if errflg
raise ClientCertTestError.new(jsondata.force_encoding("utf-8"))
end
rescue
#jsondata = nil
end
return jsondata
end
end
class ClientCertTestError < StandardError
end
# ----------------
# run
cct = ClientCertTest.new
cct.use_client_cert = true
endpoint = "https://localhost/index.html"
postdata = { "hoge" => "tara" }
jsondata = cct.request_get(postdata, endpoint, true)
p jsondata
p ""
jsondata = cct.request_post(postdata, endpoint, true)
p jsondata
#少々コードが冗長ですが、まあご愛嬌で(^^
はい。そしたら実行して見ます。
実行してみる
$ ruby ./clienttest.rb
"<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</title>\n<style>\n body {\n width: 35em;\n margin: 0 auto;\n font-family: Tahoma, Verdana, Arial, sans-serif;\n }\n</style>\n</head>\n<body>\n<h1>Welcome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.</p>\n\n<p>For online documentation and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCommercial support is available at\n<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n<p><em>Thank you for using nginx.</em></p>\n</body>\n</html>"
""
"<html>\r\n<head><title>405 Not Allowed</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>405 Not Allowed</h1></center>\r\n<hr><center>nginx/1.10.3</center>\r\n</body>\r\n</html>"
前者が GET で、後者が POST です。
GET はうまくいっている感じですね。
POST は、 nginx の場合静的ファイルに対しての POST は 405 を返すらしいので、まあ正しい反応ということで。。。
nginx + fastcgi + bash で動作確認
#cgi に bash を使う場合は Shellshock攻撃 に注意しましょうね!
がしかし、それだとあまりにもあれなので、一応 POST もちゃんと返すか確認します。
というわけで、とりあえず fastcgi をインストールする。
→ https://qiita.com/hmikisato/items/c793ced0ba2695a89de6
$ apt-get install fcgiwrap
fastcgi の設定は、特に変更しなくても大丈夫でしたので、そのままで実行。
$ /etc/init.d/fcgiwrap start
nginx側の設定を修正。以下を追加。
location ~ \.cgi$ {
root /var/www/cgi;
include fastcgi_params;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
で受け側作成
→ http://www.koikikukan.com/archives/2014/04/11-015555.php
$ cd /var/www/cgi
$ vi test.cgi
#!/bin/bash
cat <<EOF1
Content-Type: text/html
<html>
<head><title>Test</title></head>
<body>
EOF1
cat $QUERY_STRING
cat <<EOF2
</body>
</html>
EOF2
ruby のコードも endpoint のところを index.html
→ test.cgi
に修正。
endpoint = "https://localhost/test.cgi"
で実行すると。。。
$ ruby ./clienttest.rb
"<html>\n<head><title>Test</title></head>\n<body>\n</body>\n</html>"
""
"<html>\n<head><title>Test</title></head>\n<body>\nhoge=tara</body>\n</html>"
エラーは出ないみたいですね。
GET(前者)の方、$QUERY_STRING
が表示されないのはわかりませんが、とりあえず POST の方もいけてるみたいなので、これで OK ということで?