あすたぴのブログ

astap(あすたぴ)のブログ

暗号技術入門を読んだ

暗号化周りの知識が全くなくて、SSL/TLSやその他、周辺技術をを扱うにあたって非常に困った。言語ごとにライブラリがあるにはあるが、詳細はOpenSSLのドキュメントを読んだください。とか書いてあったりして、そもそもの知識がなければ何をどうすればいいかはわからなすぎた。実際、知らない人が使うものではないのだと思う。 というわけで、早急に知識が必要。だけど数学的なことはわからない。そこでこの本を読むことにした。

暗号技術入門 第3版

暗号技術入門 第3版

本書は数学的なことを控えめにし、暗号技術の概要をうまく説明してくれる本になっていた。ざっくりいうと以下の感じ

まぁ目次とほぼ同じなんだけど、単語を見ると大体聞いたことがあるのではないかと思う。何かしらのプログラムを書くときになんとなく使ってきたのではないだろうか。最後にSSL/TLSがでてくるがこの技術はそこまで説明した暗号技術をすべてといっていいほど使用している。その為、最初からしっかりと読み進めることで理解ができるようになっている。

これを読むまでは公開鍵暗号を至るところで自分で使用しておいて、その中身として何をしているかを理解していなかった。詳細な数学のことは読んでもわからないが、なぜこのアルゴリズムが解読困難なのか、なぜ公開鍵、秘密鍵に別れているのか、なぜ、秘密鍵で暗号化したものを公開鍵で復号化できるのか。がわかるようになる。 あとは乱数とか。乱数にも種類があり、弱い擬似乱数、強い疑似乱数、真の乱数という3つに本書では分類している。昔、公開鍵のペアをWindowsのアプリで作るときにマウスをぐりぐりしていたことがある。それが何をしていたのかがわかった。真の乱数というのは再現不可能であることが必要でマウスのぐりぐりなどは再現ができない。それを乱数の元にしていたということだった。

この本は今後SSL/TLS化が必須になってくる時代でエンジニアとして生きるのであれば一度は読んでおいてもいいのではないかと思った。またSSL/TLSプロトコルについて詳細に知りたい場合はReal World HTTPも併せて読むといい。

暗号技術入門 第3版

暗号技術入門 第3版

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

https化の話しとLet’s Encrypt、ACMEプロトコルについて

近頃、https化が話題になっている。

https://japan.cnet.com/article/35100589/

chromehttpsではないサイトに警告を出すようになった。 それを受けて、このはてなブログなど個別に与えられるサブドメインがhttpであることが問題になったりしている。はてなはてなブログhttps化を進めていることを発表している。また現時点では同じようなサービスではMediumが独自ドメインhttpsが使用できる。他のサービスではBASEやSTORES JP(http://officialmag.stores.jp/entry/kaigyou/kinou-ssltaiou)が対応している。

https にすると何がいいのか

色んなところですでに話されていることで知っているだろうけども。 httpsssecueres でhttpをsecureにしたということ。 具体的にはインターネットを流れている情報を暗号化してやり取りをするようになる。 暗号化されていないと何が問題なのかというと、パスワードやクレジットカードの番号をそのまま送ることになる。 そのまま送るといってもその情報がどのように送られているかイメージが出来ないと思う。インターネットの通信というのは通信先のIPアドレスを特定し、そのIPアドレスに向かってルーターとかをいくつか経由して相手に通信先に届く。その経由するところに、パスワードやクレジットカードが渡るということになる。悪意を持ってデータを収集されていなければ何事もないかもしれないが、リスクがあるという話しになる。

また他には、httpsでなければ使用できない技術が増えてきている。例えば、httpといってもhttpにはいくつかバージョンがあり一般的には1.1というバージョンが使用されているが、2.0というバージョンも存在していてそれはhttpsでなければ使用ができない。 service workerというブラウザ上で動かせるプログラムもhttpsが必須になっている。

なぜhttpsにするのが大変なのか

暗号化されていて、安全ならみんなhttpsにすればいいんじゃないか?と思うよね。 昔はhttpsを使っているサイトだとしても重要な情報をサブミットするとき、ログイン時などだけhttpsを使用する。という運用が行われていた。それは何故かというと暗号化には復号化という処理が伴うのだが、この2つの処理をするにあたりパソコンのCPUを使用する。この処理はそこそこ時間がかかるもので全通信をhttpsにするとサイト全体が重いということになり、ユーザーの体験が損なわれる。それで重要な情報をやり取りしないページではhttpにしサイトを軽くしていた。 技術は進化し、パソコンのCPUは強くなり、暗号化に使用しているアルゴリズム(暗号の種類)もより計算量が少ないものになったりした。それによって暗号化、復号化にかかる時間は減り、すべてのページを安全にしたほうがいいんじゃない。という成行き。だと思う。

とはいえ、httpにsを付けるにはどうすればいいのか。 それを行うためには、SSL証明書というものが必要になる。(現在使用されているのはTLSだが、SSLと呼ぶことにする) SSL証明書というのは暗号化を行うために必要であるものと共に、そのサイトの正当性を証明するものでもある。 SSL証明書を発行するためには、https://jp.globalsign.com/ こういうところで購入することになる。SSL証明書にも種類があり、一番安いDV証明書でもここを見る限りは年34800円かかる。気軽に自分のサイトを作って公開できたりしていたインターネットはどうなっちゃうだよ。って思う値段だ。また証明書を発行するのに暗号化に使用する鍵を作成したりする。(むずかしい) とてもじゃないが、趣味レベルの個人サイトで行うのは無理だ。

https化してくれるサービスはそれだけお金払ってるの?

ここでタイトルにあるLet's Encryptというのが出て来る。無料で証明書を発行してくれる認証局になる。 ただ、DV証明書しか発行できなかったり、証明書の期限が90日だったりと制限はあったりする。とはいえ、34800円がタダになるのはすごい。BASEなどのサービスはユーザーの代わりにLet's Encryptに申請して証明書を取得している。ことになる。

ACMEプロトコル

とはいっても従来の認証局のような手続きを1ユーザー、1ユーザーに対して行うのは骨が折れる。それを解決する為に策定が進められているのがACMEプロトコル、Automatic Certificate Management Environmentの略で証明書の自動発行、管理の方法を取り決めている。 Let's Encryptはこれに従いつつ自動で証明書を発行できるサーバーになる。そのサーバーはOSSで開発されている( https://github.com/letsencrypt/boulder ) RFCgithubで議論されてたりする。 ( https://github.com/ietf-wg-acme/acme )

雑にACMEプロトコルを説明すると以下になる

  • ユーザー登録
  • 申請
  • チャレンジ
  • 証明書取得

ユーザー登録し、このドメインの証明書をくれー。ってお願いして、チャレンジと呼ばれるドメインを所持していることを証明する作業を行い。証明書発行側でそれを確認できたら証明書を発行できるようになる。 これをプログラムで自動に行うことでユーザーが使用する証明書を取得する。

ACMEプロトコルの詳細は気が向いたら書く。

Railsで暗号化するときのメモ的なアレ

背景

ログインに使用するパスワードは不可逆な暗号化を行って、DBに保存にするのは一般的。 それとは別でDBに保存しておきたいんだけど普通に生データとして持つとセキュリティ事故でデータが漏れた場合にそのまま見えてしまう困るようなデータを可逆な暗号化で保存しておきたい。データが漏れないようにセキュリティを強化すると共に、万一データが漏れた場合に容易に流出しないように2重の対策をすることが目的。

ActiveSupport::MessageEncryptor

ActiveSupport::MessageEncryptorを使う。 http://api.rubyonrails.org/classes/ActiveSupport/MessageEncryptor.html

RubyのOpenSSL::Cipherのラッパーだと思う。 https://docs.ruby-lang.org/ja/latest/class/OpenSSL=3a=3aCipher.html

デフォルトの暗号化方式として aes-256-cbc が使用される。 暗号化方式については詳しくないのでそこの説明はできない。後日ちゃんと学びたい。

サンプルにあるように、以下のように ActiveSupport::KeyGenerator を使用して暗号化に使用する鍵を生成する

salt  = SecureRandom.random_bytes(64)
key   = ActiveSupport::KeyGenerator.new('password').generate_key(salt, 32) # => "\x89\xE0\x156\xAC..."

ユーザーのデータを暗号化する場合は、saltはユーザーごとに生成して保存しておく。saltは漏れても問題がないデータになる。 パスワードは一意の情報を用意するがこれは漏れてはいけない。環境変数などでアプリ実行時に渡す形にする必要がある。

その後は、その鍵から ActiveSupport::MessageEncryptor のオブジェクトを生成して暗号化、復号化を行う。

この処理はそれなりに重い処理になる為、頻繁に行うと辛いことになる。

いまの自分にわかってるのはこの程度なのでメモレベル

ECS環境構築時のポイントをまとめておく

また作るときにハマると辛いからね。

SSHして見に行ってもいいんだけど、入らなくても状況がわかるようにしておくと楽。

大前提

すべてのdockerイメージで実行するプロセスのログはstdout,srderrに出しておく。 普通のアプリケーションだとログファイルに出力してfluentdとかで収集して、S3に保存しておいたりするんだけど、dockerでは標準出力以外は拾いません。 なので、nginxとかunicornとかのログはstdoutに設定しておきます。

これは普段開発する時も同じようなコンテナ構成にして、普段から標準出力で開発するようにしておくといい。

awslogsログドライバーを最初から設定する

こちらです。

これを設定すると、cloudwatch logsにdockerのログを送ってくれます ここに送られる内容はdockerコンテナに対して、docker logs コンテナ名 or コンテナIDのコマンドを叩いたときに出力されるものと同じです。

awslogsを簡単に見れるようにしておく

https://github.com/jorgebastida/awslogs awslogsコマンドを使うと、指定し cloudwatch logsのログをtailする感じで見れる。

ここまで設定しておけば、

ECSクラスターにコンテナを配置しているんだけど、何故かすぐに停止する。 ヘルスチェックが通らないというトラブル時にも対処が簡単になる。

ホストOSを通して通信できるようにする

コンテナをたてるEC2インスタンスにイカを設定しておく。 たぶん、デフォルトで設定されているはずなんだけどいつからかdockerコンテナから外へ出れなくなっていたので、一応設定しておく。

sysctl -w net.ipv4.ip_forward=1

fs.inotify.max_user_watchesを増やしておく。

inotifyの監視対象ファイル数の上限を上げる(Rails起動時に足りなくなる場合がある)

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

コンテナインスタンスで、dockerが使用するポートを全て開けておく

32768 ~ 61000番です。 ここにのってる。