Friday, June 27, 2014

LINE「独自暗号化」のメリットと安全性について

LINEが使用している「独自の」暗号化手法について、情報が一部開示(参照:LINEの暗号化について « LINE Engineers' Blog)され、Twitterでもやりとりをしたので、まとめてみる。

■なぜTLSを使わないか

TLSではなく、1パスのメッセージ暗号化を使っている理由については、Adopting SPDY in LINE – Part 2: The Details « LINE Engineers' Blogに以下のような記載があり、TLSを使うことによるレイテンシの増加を懸念しているためと考えられる。
3G mobiles networks normally operate at slow speeds. (中略)If the connection changes modes when the user sends a message, we are forced to wait until we receive the server response before we can do anything else.

■どのような暗号化手法なのか

RSA暗号に加え、ブロックサイズが128bitの共通鍵暗号を用いており、共通鍵暗号の鍵をサーバのRSA公開鍵で暗号化し、共通鍵暗号で暗号化されたメッセージとともに送信していると考えられる(参考:ツイート 1, 2, 3, 4)。

おそらく、リクエストを送信する度に、大筋で以下のようなことを行っているのではないか。
# AES鍵を生成
AESKEY=`openssl rand -hex 16`注6

# 初期化ベクタを生成
IV=`openssl rand -hex 16`

# AES鍵をサーバの公開鍵で暗号化注1し、HTTPリクエストヘッダとして送信
echo -n "$AESKEY" | openssl rsautl -encrypt -pubin -inkey server-public.pem -in /dev/stdin | openssl base64

# POSTリクエストのボディをAESを利用して暗号化し、送信
echo -n "$content" | openssl enc -aes-128-cbc -in /dev/stdin -K "$AESKEY" -iv "$IV" | openssl base64

■この手法は安全か

RSAやAESといった暗号アルゴリズムは正しく使わないと脆弱になるし、どのように使っているかは今回開示されていない。とは言え、このように良く知られた部品(PKCS #1 v1.5とAES-CBC)を単純な形で組み合わせているのであれば、問題がある可能性は低い注2。実際のところ、上記推測例は、秘話化という観点からは僕には特に問題がないように思える。問題があるなら誰か教えてほしい注3

手法の推測が正しいならば、「通信全体について、他国からアクセスすることは不可能」注4ということだし、「システムに直接侵入するのではなく、通信回線とサーバーの間でワイヤタッピング」注5することにより情報が漏洩している可能性は極めて小さいのではないか。

■同様の暗号化を行いたい場合はどうすればいいか

ウェブアプリケーションなどで使用が容易なメッセージ暗号化手法については、現在、JSON Web EncryptionがIETFで標準化の最終段階にあります。完全性保護も含まれているし、標準化団体での安全性検証が行われているこちらを使いましょう。対応しているライブラリについてはJSON Web Token (JWT) - OAuth.jpが参考になるかもしれません。


注1: この例ではPKCS #1 v1.5を使用しているが、RSA-KEMが、より望ましいかもしれない
注2: CBCモードの使用法については、NISTが出しているガイドライン(NIST SP 800-38A)と、CRYPTRECによる安全性評価を参照
注3: リプレイ攻撃への対策や完全性保護については、この例には含めていない
注4: 参照:LINE、改めて傍受を否定 「暗号化後データは独自形式、解読は不能」 - ITmedia ニュース
注5: 参照:韓国国情院がLINE傍受:FACTA online
注6: 生成している鍵とIVの長さが64bitになっていたのを修正 (11:21am)

Thursday, June 5, 2014

Unix系OSの権限分離の変遷について(もしくはなぜ、アプリ単位の権限分離が求められるようになったか)

[ブコメした件について。大筋でおかしなことは書いてないと思いますが、出典は確認していません]

Unix系OSにおける権限分離は、伝統的に、利用者ごとに異なるuser idを割り振り、これを用いてアクセス制御を行うという方式で実現されてきた。また、デーモンプロセスについては、不要な権限付与を避け、デーモンプロセス間の相互作用を抑制するために、デーモンごとに専用の「user id」を発番するのが一般的な慣習とされるようになったという経緯がある。

しかし、2000年代に入ると、インターネットの普及とあいまって、クライアントサイドではこのような「利用者ごと」の権限分離では不十分という考え方がされるようになってきた。具体的には、

  • (オンラインバンクのパスワードに代表されるような)攻撃価値が高い情報をOS内に保存・利用するのが一般的になった
  • (限定された流通経路で入手するソフトウェアのみならず)インターネットからダウンロードしたプログラムを実行するという慣習が一般的になった
のようにユーザー行動が変化した結果、高いセキュリティが要求される処理と、セキュリティよりも利便性を重視したい処理が、同一のアクセス権限のもとに併存するようになったのである。だが、そのような状況は危険である(ネットからダウンロードしたマルウェアによって重要な情報が流出する可能性がある)。よって、同一ユーザー権限のもとで動作するプログラム間においても、アクセス権限の分離の必要性が認められるようになってきたのだ。

このため、iOSやAndroidのようなスマホOSにおいては、利用者ごとではなくプログラムごとに異なる「user id」を割り振り、互いのデータにアクセスできないような仕組みになっている。

一方でOS Xのような、より以前からあるUnix系OSにおいては、このような仕組みに移行することは現実的でないため、Keychainのように、秘匿性の高い情報についてのみプログラム単位でのアクセス制御機能を提供することで、問題の緩和が計られている。

以上のような経緯があるので、クライアント上で一般ユーザー権限で動作するプログラムにおいて、(psコマンド等を通じて情報が流出する問題がある)環境変数に認証情報を格納するのは避けるべきと言えるだろう。