"VNC password" を設定すると通信が平文になるから、注意して使おう
Raspberry Pi OS with Desktopをインストールすると標準同梱されるRealVNCへ、RealVNC Viewer以外のVNCクライアントから接続すると "No matching security types" と表示されて接続に失敗します。
検索をすると「Authenticationを "VNC password" に設定する」という手が紹介されているのですが、なぜ接続できるのか、そして副作用の有無について解説されているものが無かったので、調べてみたらひどい目にあったというお話です。
先に結論
文末にも同じこと書いてありますけど、お急ぎの方向けに。
- "No matching security types" の対策として「Authenticatiionを "VNC password" に設定する」と、様々なVNCクライアントから接続できるようになる代わりに平文通信になる。
- 暗号化通信をしたければ、サーバーとクライアントのVNC実装は同じものを使おう。
- どのような条件でも、安心してVNCを使いたいならSSHかstunnelの併用を。
"VNC" とは?
多くの実装が存在するVNCですが、 RFB(Remote FrameBuffer)というプロトコルを用いて、画面やキーボード/マウスといった入出力をネットワーク越しに送受信するソフトウェアを "VNC" と定義するのが合ってそうです。
そんな "VNC" の歴史と今
1999年にオリジナルの "VNC" (ソフトウェア名としてのVNC) が登場して以来、オープンソースだったこともあり、多くの派生ソフトウェアが●●VNCとして生まれました。
Wikipediaによると "VNC" は開発を停止しており、現在はRealVNCが後継とのことです。ちなみに "VNC" VNC Openという名称でこちらからダウンロード可能です。
RFBの仕様とバージョン
VNCのプロトコルであるRFBはRFC 6143で 3.3, 3.7, 3.8 の3バージョンが公開されていますが、その他に "4.0" と "5.0" が存在します。
この二つはSecurity analysis of the RFB 5.0 protocol(PDF)とVNC® Connect security whitepaper 1.4(PDF)にその存在が書かれていますが、仕様は非公開のプロプライエタリなプロトコルのようです。
ちなみに、Raspberry Pi OSでインストールされるrealvnc-vnc-server 6.7.2.42622に接続すると RBF 005.000
という文字列が返却されます。
3.xについては先ほど紹介したRFCの他に、VNC実装の一つであるTigerVNCのチーム(なのかな?)によっても仕様が公開されています。
また RFB 3.7 と RFB 3.8 はそれぞれRFCベースの日本語訳もあります。
※ありがたいことです
RFBにおける、通信の暗号化手法の決定方法
RFBでは、サーバークライアント間の「認証手法」と「暗号化手法」は "Security Type" という1つのパラメータのネゴシエーションで決定されます。
まずサーバー側から受け入れ可能なSecurity Typesをクライアントに提示し、クライアントがその中から選択して認証を開始します。認証成功後はinitialisation phaseへと移行していく流れです。
Security Type に仕様は、まず認証手法が定義されて、そのsubtypeとして暗号化手法が定義されています。
例えば認証手法 = VeNCryptの場合、subtype は以下のようなマトリクスになります。この中には暗号化手法が含まれているわけです。
- | 認証無し | カスタムパスワード認証 | PAM(OSアカウント等)認証 |
---|---|---|---|
暗号化なし | None | VncAuth | Plain |
匿名のTLS暗号化 | TLSNone | TLSVnc | TLSPlain |
証明書によるTLS暗号化 | X509None | X509Vnc | X509Plain |
一方、認証手法 = VNC Authentication(VeNCryptの時のVncAuth subtypeとは異なる)にはsubtypeがありません。これは暗号化手法が未定義となるため通信は平文で行うことになります。
このようにRFBは「認証手法」に「暗号化手法」が連動した仕様となっています。
VNCの「Authenticatiionを "VNC password" に設定する」と、何が起こるのか?
ここからが本題です。
"No matching security types" の対策として「Authenticatiionを "VNC password" に設定する」とVNCの通信がすべて平文になります。
「Authenticatiionを "VNC password" に設定する」というのは、Security TypeでいうところのVNC Authenticationを、サーバー側に設定したことと同義であり、この場合は平文での通信になることは先の章で解説した通りです。
この VNC Authentication は、どのようなVNCクライアントでも実装している基本的な機能であるため、接続できるようになるわけです。
パケットダンプで検証
サーバー側のデフォルトの状態(VNC Authenticationをセットしていない)状態と、VNC Authenticationをセットした時で、サーバーが返却する Security Type の違いが以下の通りです。
VNC Authenticationをセットしていない状態
VNC Authenticationをセットした時
VNC Authenticationをセットした時には、Security type に VNC(2) (仕様書だと "VNC Authentication" のNumber が 2 だから VNC(2) という表示) が追加されたのがわかります。
VNC(2) が返却される環境で、クライアントにTigerVNC viewerを使い、その後続けてみると、Authentication type selected by clientで見事 VNC(2) を選択しています。
VNC(2)以降の通信も、もちろん暗号化指定は無いため生データが流れます。
逆に VNC Authentication をセットしていない場合でクライアントにTigerVNC viewerを利用すると、(上段の画像で)提示された5つのSecurity Typeは、どれもサポートしていないため "No matching security types" となるわけです。
全体のシーケンスも掲示しておきます。
RealVNCやmacOSの「画面共有」の暗号化はどのように行われているのか?
こうなってくるとRealVNCや、VNCを利用しているmacOSの画面共有は暗号化されているのか気になりますね。結論から言えば、暗号化されますが条件があります。
その条件とは 「RealVNCならRealVNC Viewerを、macOSの画面共有ならmacOSが標準で提供しているVNCビュワーを使う」 ことです。
これは、暗号化(の指定)がSecurity typeで行われるのでは無く、画面の転送に使うエンコーディングを設定するClient set encodingで行われるためです(おそらく)。
というのは、エンコーディングにAppleやRealVNCの名前があり、エンコーディングの中に暗号化実装を組み込んでいるのだと推測できます。
実際パケットダンプを行うと、認証後はVNCのフレームでデコードできないパケットになりました。残念ながら、どのような暗号化がされているかは不明でした。うわ、私のバイナリ力が低すぎ。
ちなみにSecurity TypeでもRealVNCやApple Inc.の定義がされています。認証の仕組みも独自ということですね。
結果、この独自実装を受け入れることができるのは、専用クライアントということで「RealVNCならRealVNC Viewerを、macOSの画面共有ならmacOSが標準で提供しているVNCビュワーを使う」となるわけです。
RealVNCでの暗号化実装
RealVNCについてもmacOSと同様ですが、Security analysis of the RFB 5.0 protocol(PDF)にRA4(RSA with ASE version 4)という表記があります。聞きなれないのですが、RBF 4.0(?)で使われていたRA2neの実装解説がありました(未検証)。オープンな仕様を利用した独自実装といったようです。
macOSの「画面共有」の様子
macOSの画面共有に対してVNCクライアントをつなげてみると、Security typesは30,33,35,36 と提示されます。仕様通りですね。
ちなみにですが、macOSの「画像共有」では RBF 003.889
というバージョンを返してくれます。なかなかの独自実装ぶりです。
macOSの画面共有やRealVNCでも設定できる「VNC Authentication」
RealVNCもmacOSの画面共有も、VNC Authenticationがセットできます。
それにより、様々なVNCクライアントから接続できるようになる代わりに、平文通信になるということを覚えておきましょう。
TigerVNCは「VNC Authentication」でも暗号化されている
TigerVNCでVNC Authenticationが設定された場合、サーバーからのSecurity typeは VNC(2) と VeNCrypt(9) の二つが提示されます。これをTigerVNC viewerで受けた場合、TigerVNC viewerは VeNCrypt(9) を選択して認証を依頼します。
VeNCryptには、VNC Authentication(= カスタムパスワード認証)にひもづくsubtypeが3つあり、クライアント側で選ぶことができます。
TigerVNC viewerのオプション画面
このうちTLS with ... で接続できれば、TLSによる暗号化通信ができるというわけです。
一般的にはTLS with anonymous certificates(= TLSVnc)が選択されます。
VNCを使う時には、SSHかstunnelによる経路暗号化をおすすめします
ここまで解説してきた通り、意図せずにVNCの通信が平文になることがあります。また、気づきにくいというのも少し気がかりです。
"VNC 暗号化" で検索すると、SSHのポートフォワーディングの情報が見つかりますので、使えるでしょう。
それ以外にも、stunnel を使ったTLS終端との組み合わせも検討できます。
通常であればTLS終端となるサーバーを、例えばnginxなどで準備する必要があります。3G/LTE/5Gといったセルラー通信を利用したリモートアクセスサービス「SORACOM Napter」はポート転送サービスですが、TLS終端機能もあります。そのため、stunnelでSORACOM NapterにTLS接続&終端させてから、セルラー通信をしているVNCサーバーにポート転送することも可能です。(そのうちブログ書きます)
まとめ
- "No matching security types" の対策として「Authenticatiionを "VNC password" に設定する」と、様々なVNCクライアントから接続できるようになる代わりに平文通信になる。
- 暗号化通信をしたければ、サーバーとクライアントのVNC実装は同じものを使おう。
- より具体的な組み合わせ例は「VNCの通信を暗号化する、OS毎のベストプラクティス」として近日公開予定!
- どのような条件でも、安心してVNCを使いたいならSSHかstunnelの併用を。
便利なVNCだからこそ、気をつけて使いたいものですね!
― 松下享平 (Max / @ma2shita フォローやFF外からのメッセージwelcome!!)
お付き合いください:ひどい目にあった話。
いやー、気楽な気持ちでVNCの事を調べたら、こんなに奥深かったとは!油断しました。特に、RFBにバージョンが存在して、しかも3.8と5.0の双方が現役という自体は予想していませんでした。これも、4.0以降がプロプライエタリになったため、3.8をベースに機能拡張がされ始めたことが原因でしょう。macOSなんかRBF 003.889とか返却しますし!
結局GWの1日(本当に20時間くらい)が溶けました。その代わりブログ2本という成果なので…うーん、よし!(現場猫)
EoT
Discussion