はじめに
VPoPの岩田です。本記事は、先日より開始しているMQTT5連載の第4回目になります。
第4回目となる本記事では、MQTTで用いられる認証方式についてご紹介します。 MQTT3.1.1で定義されていた方式について触れた後、MQTT5で追加された方式について解説します。
すでに公開されている連載記事は、末尾のリンクからご覧いただけます。
当社プロダクトの簡単なご紹介
弊社アプトポッドでは、IoTシステムの通信バックエンドとしてデファクトスタンダードとなっているMQTTに代わる選択肢として、独自開発の通信ミドルウェア「intdash」 を開発・提供しています。 intdashでは、MQTTの旧バージョンであるMQTT 3.1.1が抱えていたスケーラビリティやパフォーマンスに関わる課題を、MQTT5とは異なるアプローチによって解決しています。
intdashについては、連載1日目の記事でももう少し詳しく触れていますので、よろしければこちらの記事もご覧ください。
また、intdashで使用している当社独自の通信プロトコルについても以下の記事で解説していますので、こちらも併せてご覧ください。
また、システム構築の受託やご相談も受け付けておりますので、IoTシステムの構築でなにかお困りのことがあれば、お気軽に弊社までお問い合わせください。
それでは、本編に入っていきます。
MQTT 3.1.1 から継承している認証方式
従来のMQTT 3.1.1 では、CONNECTパケットによりユーザー名とパスワードを送信することにより認証を行うことが可能でした。 基本的にはBASIC認証に使用される想定の仕組みでしたが、現在ではパスワードとしてトークンを渡すなど、BASIC認証以外の認証でも活用されるようになっています。
また、MQTTのプロトコルが持つ機能ではありませんが、MQTTの下回りとして使用するプロトコルの認証機能を使用することも可能です。たとえば、MQTT over TLSを使用すれば、TLSレベルでクライアント認証を設定することができます。また、MQTT over WebSocketを使用すれば、WebSocketへアップグレードする前のHTTPのレベルで、Web技術を活用した様々な認証を設定できます。
これらの方式は、MQTT5でも変わらず使用できます。
ユーザー名/パスワードによるBASIC認証
可変ヘッダー内の有効化フラグ
CONNECTパケットの可変ヘッダーには、Connect Flags(接続フラグ)というフィールドが存在します。
接続フラグには、Willやセッション初期化に関するフラグの他に、ユーザー名やパスワードを使用するかどうかのフィールドが存在します。 これらを有効にすることによって、ユーザー名とパスワードを使用した認証を有効化できます。
CONNECTパケットの可変ヘッダーに関する仕様の詳細は 「3.1.2 CONNECT Variable Header」で定義されています。
ペイロード内の実際のデータ
実際のユーザー名やパスワードは、CONNECTパケットのペイロードで送信されます。 CONNECTパケットのペイロードには、ユーザー名やパスワード以外にも、以下のような情報が含まれます。
- Client Identifier(クライアント識別子)
- Will Properties(Willのプロパティ)
- Will Topic(Willのトピック)
- Will Payload(Willのペイロード)
- User Name(ユーザー名)
- Password(パスワード)
このうち、クライアント識別子だけが必須のフィールドで、それ以外のフィールドは可変ヘッダー内の接続フラグで有効化されているもののみが含まれる仕様となっています。 格納のされ方としては、長さと実際のデータをセットで1つとして、有効化されているフィールド分ただ羅列するようなフォーマットになっています(格納順序が決まっており、上に箇条書きで記載した順番になります)。
言葉だけでは若干分かりにくいため、実際の格納例を以下に示します。
可変ヘッダーの接続フラグでユーザー名やパスワードを有効化し、ペイロードに実際のデータを含めることで、CONNECTパケットによる認証情報の送信が可能になります。
MQTT5で加えられた変更
ユーザー名とパスワードによる認証の方法について、基本的な構造はMQTT 3.1.1から変更されていません。 ただし、1点だけ特筆すべき変更点があります。それは、ユーザー名を有効化しないでパスワードだけを有効化することができるようになった点です。
前述のとおりMQTT 3.1.1におけるユーザー名とパスワードのフィールドはBASIC認証を想定した設計になっていたため、ユーザー名なしでパスワードを送信することは許可されていませんでした。
MQTT5では、実際の使われ方としてパスワードフィールドがパスワード以外の認証情報の伝達に広く使用されていることを鑑みて、ユーザー名を設定しないでパスワードフィールドを使用することが許容されました。
この背景については、「3.1.2.9 Password Flag」のセクションで Non-normative comment として、わざわざ注記されています。
Non-normative comment
This version of the protocol allows the sending of a Password with no User Name, where MQTT v3.1.1 did not. This reflects the common use of Password for credentials other than a password.
MQTTの下回りでの認証(TLS、WebSocket等の利用)
前述の通り、MQTT自体のプロトコル仕様による認証方式以外に、MQTTの下回りとして使用するプロトコルの認証方式を利用することもできます。
MQTT自体は経路暗号化などの機能を持たないため、安全でないネットワークでの利用ではMQTT over TLSの形式で使用することが多くあります(いわゆる MQTTS)。 下回りにTLSを使用する場合には、クライアント証明書を使用することでクライアントを認証できます。
また、インターネットを介した情報のやりとりでは一般的にHTTPなどのWeb技術を利用することが多く、MQTTもWeb上での通信技術のひとつであるWebSocket上でのやり取りに対応しています。 WebSocketを使用する場合、まずHTTPで接続したあとにWebSocketのコネクションへアップグレードするというシーケンスを取るため、 HTTPでの接続の際にWeb技術が持っている様々な認証方式を採用することができます。
これらの方式は、MQTT自体の仕様ではなく、MQTTを動かす下回りの仕様を利用したものなので、MQTT5でも変わらず利用できます。
MQTT 5で追加された新しい認証方式
ここまでの認証方式は、MQTT3.1.1から大きく変更されていませんでした。 ここから、MQTT5で新たに追加された方式について解説していきます。
MQTT5で追加された認証方式は、「4.12 Enhanced authentication」 のセクションで定義されています。
MQTT 3.1.1で定義されていた、CONNECTパケットによるユーザー名とパスワードの送信による認証では、まずクライアントがCONNECTパケットを送信し、次にサーバーがCONNACKパケットを返却するという、1往復のやり取りによる認証しかサポートできませんでした。
MQTT5では、CONNECTパケットとCONNACKパケットの間にAUTHパケットによるやり取りを定義することで、チャレンジ/レスポンス形式など複雑な認証方法をサポート可能にしています。
MQTT5で追加された認証方式の概要
- CONNECTパケットへのプロパティの追加
- AUTHパケットの追加(追加情報のやり取り用)
- 再認証フローの追加
CONNECTパケットへの変更点
CONNECTパケットのVariable Headerに含まれるプロパティに、Authentication Method(認証メソッド)とAuthentication Data(認証データ)が追加されました。
認証メソッドは、その名の通り認証に使用する方法を指定する任意の文字列です。認証メソッドに値を設定することで、Enhanced Authenticationが有効になります。 基本的にはSASL(Simple Authentication and Security Layer、RFC4422)の登録名を使用することが想定されているようですが、それ以外の文字列も使用できるそうです。
- Wikipedia - Simple Authentication and Security Layer
- RFC4422: Simple Authentication and Security Layer (SASL)
認証データは、指定された認証メソッドに固有のデータが格納されるプロパティです。 どのようなデータをどのような形式で格納するかは認証メソッドごとに異なるため、MQTT5の仕様では定義されていません(情報を伝達するための箱としてのプロパティのみが定義されています)。
AUTHパケットによる追加情報のやり取り
前述の通り、CONNECTパケットの認証メソッドプロパティに、認証方式を表す文字列を設定することでEnhanced Authenticationが有効になります。 Enhanced Authenticationが有効になった状態であれば、AUTHパケットによる追加情報のやり取りが可能になります。
使用する認証方式において、クライアントがまずデータを送信する必要がある場合は、CONNECTパケットの認証データプロパティでデータを送信します。 その後、認証を完了するために何らかのデータをサーバーが返却する必要がある場合は、サーバーからAUTHパケットを返送できます。 さらに追加のシーケンスが必要であれば、認証に必要なやり取りが完了するまでクライアント・サーバー間で何度でもAUTHパケットを往復させることができます。
全ての認証シーケンスが完了したら、CONNACKパケットにより認証を完了させます。
再認証フローの追加
MQTT 3.1.1 における認証は、CONNECTパケットとCONNACKパケットによりコネクションの開始時に実施するだけでした。 MQTT5では、CONNACKパケットにより認証が完了したあとのコネクション継続中であっても、再認証を実施できるようになりました。
再認証の要求は、CONNACKパケットによる認証完了後に、クライアントからAUTHパケットを送信することにより開始されます。 一連のシーケンス終了後、サーバーからAUTHパケットにより再認証完了を通知することによって完了します。
あとがき: 追加された仕様の有効性は?
これまで解説してきた通り、MQTT5のEnhanced Authenticationによって、様々な拡張認証を採用できるようになりました。確かに、認証方法が拡充され高機能になったようにも感じられます。
しかし、認証が必要なシーン(よくあるケースではインターネット越しの場合)ではWebSocketを使用することが多く、コネクション開始時にWeb技術を挟むことができればだいたいどんな認証でも実装できてしまっていた、というのが実情なのではないかと思います。したがって、Enhanced Authentication自体は実はそれほど大きなインパクトはなく、基本認証使用時のユーザー名のオプショナル化あたりの方が、ユーザー視点では有り難い変更なのではないか、というのが個人的な感想です。
認証方式については、ミドルウェアやサービス事業者がサポートする方式を決めて、ユーザーは提供される方式から選択する流れになると思います。 プロトコルレベルでEnhanced Authenticationがサポートされたことにより、これらのミドルウェア・サービスが新たな認証方式を提供し始めることも考えられますので、 新たな方式がサポートされた際にすぐに利用を検討できるよう、インパクトは小さいにせよ知識としては持っておくことをお勧めします。
おわりに
本記事では、MQTT5ににおいて新たに追加された認証方式について解説しました。 MQTT3.1.1から引き継いだBASIC認証方式が実際の使われ方に沿って使用調整されたことに加えて、新規追加されたEnhanced Authenticationについてもご紹介しました。
今回の解説は以上となります。次回以降の連載にもご期待ください。