暗号/復号関係は苦手です。かたりぃなです。
苦手な理由は、これ系は期待動作していない場合のデバッグが非常にやりにくいからなんですよね。
アルゴリズムそのものは実績がある前提だとすると、うまく動かないときはモジュール外から与えるパラメータが間違えているわけです。
鍵、IV、証明書、暗号アルゴリズム、暗号利用モード、暗号開始アドレスetc...こういうパラメータを確認して一つづつ見直しをするしかないわけです。
で、パラメータを変更して動作を追っても「あってる or 間違えている」しかわからないので、本当につらい。
数学が得意な人はもっと効率的に作業できたりするんでしょうか?
さて、今回はHTTPSとその周辺技術を触ってみます。 個人的にサーバ立ててサービス化するときも役立つと思いますので。
HTTPSとは
一言でいうとHTTPをセキュアにしたものです。
まずプロトコルの観点から整理します。
プロトコルスタック
だいたいこんな感じです。 TCPレイヤとHTTPレイヤの間にTLSレイヤを設けて、ここで暗号/復号などが行われます。
レイヤ | プロトコル |
---|---|
アプリケーション | HTTP |
アプリケーション | TLS/SSL |
トランスポート | TCP |
ネットワーク | IP |
Python-FlaskでHTTPS対応してみる(断念)
ちょっと面倒なので断念です。
HTTPS化するだけのはずが、本題以外のことを考えないといけなくて、手間かかりすぎでした。
どういうところが手間だったかというと
- アプリケーションとインフラとの結合が密になってしまう
- 当然、コードが入り乱れてきてしまう
- コード混乱の結果、リポジトリの管理どうするかとか、本題と関係ないところで悩む
アプリケーションはビジネスロジックとかに注力すべきであって、インフラ周りと密に結合した実装にするのはよくないですよね。
アプリケーションのモジュール構成をしっかり考えるという対策もありますが、今回は一般的なWebサーバを活用する方向で考えたいと思います。
というわけで、apacheとnginxを試していきます。
apacheでやってみる
apacheの設定こんな感じにすれば、とりあえずHTTPS対応できます。
証明書と鍵は後で説明します。
# vhost NameVirtualHost *:80 NameVirtualHost *:443 Include pass/apache/conf.d/*.conf
virtualhost(pass/apache/conf.d/httpd_vhosts_site.conf)
<VirtualHost *:80> ServerName local.my.api.mtg_card_detect # ~~ 略 ~~ <VirtualHost> <VirtualHost *:443> ServerName local.my.api.mtg_card_detect:443 SSLEngine On SSLCertificateFile pass/apache/server.crt SSLCertificateKeyFile pass/apache/server.key <VirtualHost>
で、この後段にお好きなアプリケーションサーバを置いておけばよさそうです。
PHPなんかだとこの方法でちゃちゃっとやっつけてもいいかもしれませんね。
アプリケーションとwebサーバを分離したい
ここから、今回のエントリの本題です。一般的にSSLオフローダ、リバースプロキシと呼ばれる方式です。
クライアントからのアクセスを一旦Webサーバで受けて、WebサーバはSSLを解きます。
SSLを解いたら、Webサーバからアプリケーションサーバへ(HTTPSではなく)HTTPでリクエストを出します。
これで次のことが実現できます
- nginxはクライアントアクセスをさばく(SSLを解く作業も含む)ことに注力
- 後段のアプリケーションサーバはロジックを実装する
いい感じの役割分担になってきました。
nginxリバースプロキシでSSLオフロードをする検討
以前やったnginxのリバースプロキシにSSLを解かせます。
一点だけ懸念がありますが、今回は気にしないことにします。まだ使わない機能なので。
何が懸念かというと、アプリケーションに必ずHTTPでリクエストが来るということは、リクエストURIが書き換わるということを意味します。
リクエストURIが書き換わると、アプリケーションが実装している盗聴対策, 認証, 認可などのセキュリティでエラーとして弾かれる可能性があります。
具体的にはOAuthとか。うろ覚えですがOAuthはリクエストURIを含めて何か作ってた気がします。またの機会に調査します。
nginxでSSLを解く
まず証明書と鍵が必要です。実験用なので自分で鍵を作って、自分で署名しましょう(通称:オレオレ証明書)。
$cd /usr/local/nginx/conf.d $openssl genrsa 2048 > server.key $openssl req -new -key server.key > server.csr # ※以下のような質問が出るが、オレオレ証明書なので全てEnterでスキップでOK。 You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []: Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: # 署名する # 実験中に期限くると困るので10年(365 x 10=3650)くらいの有効期限で $ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt
次にnginxの設定ファイルを書きましょう。 以前やったリバースプロキシの設定を書き換えています。
user nginx; worker_processes 1; pid /var/run/nginx.pid; events { worker_connections 1024; } http{ server { listen 443 ssl ; server_name local.my.proxy.server; ### SSL有効化と証明書の保存場所指定 ssl on; ssl_certificate /etc/nginx/cert/server.crt; ssl_certificate_key /etc/nginx/cert/server.key; ### プロキシ先の指定とApacheに渡すリクエストヘッダーの指定 location / { proxy_pass http://192.168.xx.xx:port/; proxy_redirect off; proxy_set_header Host local.my.api.mtg_card_detect; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } }
これでOKです。 nginxにHTTPSでリクエストを出すとmtg_card_detectというアプリケーションサーバにHTTPリクエストが出るようになりました。
感想と今後の展望
SSL対応もできたので、今後カードゲームARアプリのゲームサーバ(カード検出、分類)に対するリクエストもHTTPSで実現できる目途は立ちました。
本物の証明書はCAに発行してもらわないといけないので、実際にどうするのかは必要になってから調べることにします。
サーバ構成も少しづついじれるようになってきたので、今後のアプリづくりで有効活用したいですね。
それでは今回はこれくらいで。