目次


セキュアな IoT ソリューションの設計と構築, 第 3 回

IoT アプリケーションをセキュリティーで保護する

IoT データをセキュアに保管し、保管されたデータをセキュアな API を介して公開し、セキュアな API をモバイル・アプリや Web アプリから呼び出す

Comments

コンテンツシリーズ

このコンテンツは全3シリーズのパート#です: セキュアな IoT ソリューションの設計と構築, 第 3 回

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:セキュアな IoT ソリューションの設計と構築, 第 3 回

このシリーズの続きに乞うご期待。

クラウド・ベースの IoT アプリケーションにおけるセキュリティーの主な目標は、許可されてないユーザーがデバイスから送信される機密データや個人データにアクセスできないようにすることです。また、不正なコマンドがデバイスに送信されないようにするための対策も、IoT アプリケーションには必要になります。この全 3 回からなるシリーズの第 3 回では、IoT デバイスからのデータを扱う Web アプリとモバイル・アプリをセキュリティーで保護するためのさまざまな手法について説明します。シリーズの第 1 回第 2 回のそれぞれで、デバイスをセキュリティーで保護し、デバイスとネットワーク間にセキュアな通信を確立するさまざまな手法を詳しく説明しました。

図 1 に、この記事で説明する手法を示します。モバイル・クライアントと Web クライアントには、許可されたユーザーだけがアプリにアクセスすることを確実にするための固有のセキュリティー・メカニズムを設けてあります。アプリケーション・ロジックのコアは、IBM Cloud ベースのバックエンド・サービスに配置します。このアプリケーション・ロジックによって IBM Watson IoT Platform から (セキュアな Watson IoT Platform API を使用して) データをプルし、そのデータを分析し、デバイスの制御コマンドを送信します。

図 1. IoT デバイスのデータを扱う Web およびモバイル・アプリをセキュリティーで保護するための手法
IoT デバイスのデータを扱う Web およびモバイル・アプリをセキュリティーで保護するための手法の概要図
IoT デバイスのデータを扱う Web およびモバイル・アプリをセキュリティーで保護するための手法の概要図

この記事では、読者が IBM Cloud アプリケーションを開発およびデプロイする方法を理解していることを前提とします。IBM Cloud をまだ利用したことがない場合は、このリンク先の developerWorks の「IBM Cloud essentials」コースに沿ってチュートリアルに取り組むことをお勧めします。この記事では、Web またはモバイル・アプリをどのようにして開発するのかをステップバイステップで説明することはしません。この記事での説明は、Web またはモバイル・アプリにセキュリティー機能をどのようにして追加するのかに絞ります。

アプリケーションで受信した IoT データをセキュリティーで保護する

この記事のために私たちが作成した IoT セキュリティー・デモ・サーバー・アプリケーションは、Watson IoT のイベント・データにサブスクライブし、Watson IoT から受信したデータを Cloudant データベースに維持します。データを維持する際は、保管するデータに含まれる機密性の高い属性の一部 (IoT デバイスからのペイロードなど) を暗号化します。ペイロードは JSON フォーマットですが、Cloudant データベース内では AES 暗号化フォーマットで保管され、権限を持つユーザーがデータを取得する際に暗号化解除されます。この暗号化と暗号化解除は、ユーザーには透過的に行われます。

Watson IoT Platform へのセキュアなアクセス

IBM Cloud 内でモノのインターネット・サービスを追加すると、ユーザーのアプリケーション用に以下に示すようなアクセス資格情報が生成されます。これらの資格情報によって、IBM Watson IoT Platform へのアクセスがユーザーに許可されます。

{ 
   "iotf-service": [
        {
            "credentials": {
                "iotCredentialsIdentifier": "a2g6k44sl6r5",
                "mqtt_host": " yourorg.messaging.internetofthings.ibmcloud.com",
                "mqtt_u_port": 1883,
                "mqtt_s_port": 8883,
                "http_host": " yourorg.internetofthings.ibmcloud.com",
                "org": " yourorg",
                "apiKey": "a-yourorg-qcvoaslsqn",
                "apiToken": "weSS*RHWxJIfa_nHLV"
            },
            "syslog_drain_url": null,
            "volume_mounts": [],
            "label": "iotf-service",
            "provider": null,
            "plan": "iotf-service-asp",
            "name": "iotsecuritydemo-iotf-service",
            "tags": [
                "internet_of_things",
                "Internet of Things",
                "ibm_created",
                "ibm_dedicated_public",
                "lite"
            ]
        }
    ]
}

以下のコード・スニペットに示すように、Watson IoT Platform のイベントおよびステータス更新へのサブスクライブは簡単です。

var IotfClient = require("ibmiotf").IotfApplication;
var iotConfig = {
        "org" : org,
        "id" : "iotsecuritydemo",
        "auth-key" : apiKey,
        "auth-token" : apiToken
    };
var iotfClient = new IotfClient(iotConfig);
iotfClient.connect();
iotfClient.on("error", function (err) {
    console.log("IoTF client error: "+JSON.stringify(err, null, 4));
});
iotfClient.on("connect", function () {
    // Subscribe to status from all devices
    iotfClient.subscribeToDeviceStatus();
    // Subscribe to all events from all devices
        iotfClient.subscribeToDeviceEvents();
    });
iotfClient.on("deviceEvent", function (deviceType, deviceId, eventType, format, payload) {
    // Handle events from devices
      console.log("Device event from:"+deviceType+", "+deviceId+" of event "+eventType);
      
      insertEventToDB(deviceType, deviceId, eventType, format, payload);
});
iotfClient.on("deviceStatus", function (deviceType, deviceId, payload, topic) {
    // Handle status updates from devices
      console.log("Device status from:"+deviceType+", "+deviceId);
      
      insertStatusToDB(deviceType, deviceId, payload, topic);
});

上記のコードにより、IoT イベントを受信するたびに、そのイベントとイベントに関連付けられたペイロードが Cloudant データベースに挿入されるようになります。

Cloudant データベース内のデータを暗号化する

IBM Cloud 上の Cloudant NoSQL DB インスタンスには、常に暗号化された状態でデータが保管されます。これは、「保存状態での暗号化」と呼ばれます。Cloudant データの保護とセキュリティーについて詳しくは、このリンク先の IBM Cloud の資料を参照してください。

データは暗号化された状態で保存されますが、機密性の高いデータについては、カスタム暗号化手法を実装することによってセキュリティーを強化できます。

データを保管および取得する際の暗号化と暗号解除は、以下のコード・スニペットに示すように、業界で標準的な AES-256 アルゴリズムに基づいて実装できます。

var crypto = require('crypto');
var algorithm = 'aes-256-ctr';
var cryptoKey = 'your-key';
  
function encrypt(text){
  var cipher = crypto.createCipher(algorithm, cryptoKey);
  var crypted = cipher.update(text,'utf8','hex');
  crypted += cipher.final('hex');
  return crypted;
}
function decrypt(text){
  var decipher = crypto.createDecipher(algorithm, cryptoKey);
  var dec = decipher.update(text,'hex','utf8');
  dec += decipher.final('utf8');
  return dec;
}

特に大量のデータを処理しなければならない場合をはじめ、データの暗号化はパフォーマンスに負担をかけます。したがって、適切な手法を検討して実装する際は、この側面を考慮する必要があります。

Cloudant データベース内に保管されているデータにセキュアにアクセスする

Cloudant データベース内に保管されている IoT データにアクセスするには、以下のいずれかの方法を使用できます。

  • Cloudant API キーを共有する場合は、サード・パーティー・アプリケーションを使用します。
  • Bluemix のセキュリティー・サービスで保護された、独自のカスタム API を作成します。

Cloudant API キーを使用したサード・パーティー・アクセス

IBM Cloud 内で Cloudant DB サービスを追加すると、ユーザーのプログラム用に以下に示すようなアクセス資格情報が生成されます。プログラムからこれらの資格情報を使用することで、Cloudant データベースにアクセスすることができます。

{
  "cloudantNoSQLDB": [
        {
            "credentials": {
                "username": "your-username",
                "password": "your-password",
                "host": "your-hostname-bluemix.cloudant.com",
                "port": 443,
                "url": "https:// your-username:your-password@your-hostname-bluemix.cloudant.com"
            },
            "syslog_drain_url": null,
            "volume_mounts": [],
            "label": "cloudantNoSQLDB",
            "provider": null,
            "plan": "Lite",
            "name": "iotsecuritydemo-cloudantNoSQLDB",
            "tags": [
                "data_management",
                "ibm_created",
                "lite",
                "ibm_dedicated_public"
            ]
        }
    ]
}

資格情報のユーザー名とパスワードを使用して、以下のような Cloudant API キーを生成できます。

POST _api/v2/api_keys

生成された API キーは通常のユーザー・アカウントと同じように、読み取り/書き込み/管理アクセス権限を付与するなどして使用できます。

POST https://<ユーザー名:パスワード>.cloudant.com/_api/v2/api_keys

レスポンスは以下のような内容になります。

"password": "YPNCaIX1sJRX5upaL3eqvTfi",
"ok": true,
"key": "blentfortedsionstrindigl"

API キーには特定のデータベースに対するアクセス権限を付与する必要があります。データベースにアクセスするには、以下に示す PUT リクエストを使用します。

https://<ユーザー名>.cloudant.com/_api/v2/db/<データベース>/_security),

API キーは、Cloudant ダッシュボード (以下の図を参照) から生成することもできます。

API キーを生成するために使用できる Cloudant ダッシュボード画面のスクリーンショット
API キーを生成するために使用できる Cloudant ダッシュボード画面のスクリーンショット

API キーとパスワードのペアは、他のあらゆるユーザー・アカウントと同じように扱われます。API キーを呼び出しに渡すことで、データベースを API キーと共有し、API キーにそのデータベースに対するアクセス権限を割り当てることができます。ユーザー・アカウントを使用するのが適切でない状況では、API キーとパスワードのペアを使用してください。そのような状況に該当するのは、例えばソース・コードに資格情報が含まれている場合や、プログラムによってそれぞれに異なるアクセス権限を割り当てた複数のアカウントを作成しなければならない場合などです。

API レスポンスには、以下のプロパティーが格納されます。

  • ok - リクエストが成功すると、このプロパティーが返されます。
  • error - リクエストが失敗すると、エラー・コードを含んだこのプロパティーが返されます。
  • key - API キーを返します。
  • password - API パスワードを返します。

カスタム API を使用したサード・パーティー・アクセス

Cloudant データベースに直接アクセスできるようにすると、サード・パーティーとの統合が脆弱になり、保守するにもコストがかかってしまいます。推奨されるアーキテクチャーは、カスタム API を使用して、データベースにカプセル化層を重ねることです。カスタム API はデータベース固有の詳細を隠し、特定のインターフェース・コントラクトによってデバイス情報を返します。

IoT セキュリティー・デモ・サーバー・アプリケーション内の最初のカスタム API では、以下の HTTP リクエストを使ってデバイスのリストにアクセスできるようになっています。

http://<アプリケーション・ルート>/iotf/devices

例えば、IoT セキュリティー・デモ・サーバー・アプリケーションの Cloudant データベース内に保管されているデータの送信元デバイスのリストにアクセスするには、以下のリクエストを使用します。

https://iotsecuritydemo2.mybluemix.net/iotf/devices

IoT セキュリティー・デモ・サーバー・アプリケーション内の 2 番目のカスタム API では、以下の HTTP リクエストを使って特定のデバイスのデータにアクセスできます。

http://<アプリケーション・ルート>/iotf/devices/<デバイス>

例えば、IoT セキュリティー・デモ・サーバー・アプリケーション内で使用するデバイス「j.patra」での最後の 50 件のイベントとそれぞれのイベントのペイロードを表示するには、以下のリクエストを使用します。

https://iotsecuritydemo2.mybluemix.net/iotf/devices/j.patra

さらに、以下のようにリクエストに追加パラメーターを指定することで、特定の数のイベントをリクエストすることもできます。

http://<アプリケーション・ルート>/iotf/devices/<デバイス>?count=<数>

例えば、IoT セキュリティー・デモ・サーバー・アプリケーション内で使用するデバイス「j.patra」の最後の 5 件のイベントとそれぞれのペイロードを表示するには、以下のリクエストを使用します。

https://iotsecuritydemo2.mybluemix.net/iotf/devices/j.patra?count=5

カスタム認証プロバイダーを実装する

user および userGroup オブジェクトというカスタム認証・許可オブジェクトによって、Cloudant データベース内に保管されたデータに対するロール・ベースのセキュアなアクセスを提供します。これらの user および userGroup オブジェクトを使用するために、この記事ではカスタム認証プロバイダーを使用します。

カスタム API を使用する際のベスト・プラクティスは、デバイス・データへのアクセスに対してだけでなく、デバイスへのコマンド送信に対しても、より厳重にユーザー許可を制御することです。そのためには、Cloudant 内に useruserGroup のそれぞれを対象としたカスタム・ドキュメントのセットを作成します。

Cloudant 内のこのカスタム・ドキュメントのセットを、カスタム認証プロバイダー (IoT セキュリティー・デモ・サーバー・アプリケーションの一部として実装) のロール・ベースの認証に使用します。

カスタム user ドキュメントの例は次のとおりです。

{
  "_id": "joypatra@gmail.com",
  "recordType": "user",
  "userName": "joypatra",
  "password": "encrypted-password",
  "displayName": "Joy Patra",
  "attributes": {
    "Language": "English",
    "Country": "India",
    "emailAddress": "joypatra@gmail.com",
    "userGroup": "groupAdmin"
}

カスタム userGroup ドキュメントの例は次のとおりです。

{
  "_id": "groupAdmin",
  "recordType": "userGroup",
  "groupName": "groupAdmin",
  "roleAdmin": "true",
  "roleReader": "true",
  "roleWriter": "true",
  "displayName": "User authorization administrator group",
  "devices": ["j.patra", "a.gantait", "a.mukherjee"]
}

この記事で開発するカスタム認証プロバイダーは、Cloudant データベース内にある上記の user ドキュメントと userGroup ドキュメントを使用します。

IBM App ID を利用してカスタム API をセキュリティーで保護する

データをセキュリティーで保護し、カスタム API を介して公開した後は、次のステップとして、これらのカスタム API を認証と許可によるセキュリティーで保護します。Web アプリやモバイル・アプリが API を呼び出す際は、必要な認証資格情報を提示しなければならないようにします。また、これらのアプリには、それぞれがアクセス権限を持つ特定のデバイスのデータにだけ、アクセスが許可されるようにします。カスタム API をセキュリティーで保護する手段として、この記事では IBM Cloud 上に用意されている IBM App ID サービスを利用します。

この記事で取り上げる Web アプリケーションは、Node.js を使用して開発されています。Web アプリケーションを保護するために、Node.js 内の認証ハンドラー・メソッドは、passport 認証ミドルウェアを使用して増補されています。passport 認証ミドルウェアは、IBM App ID と Web App Strategy オブジェクトを使って初期化された Node.js passport インスタンスです。したがって、認証要求は IBM App ID によってインターセプトされて処理されます。

IoT デバイス・データへのアクセスを提供する Web アプリは、アプリケーション・ユーザーのユーザー名/パスワードの組み合わせによるセキュリティーで保護する必要があります。デモ Web アプリ内では、バックエンド・ユーザー・レジストリー (IBM Cloud Directory など) を使用して、すべてのユーザー情報を保管します。

App ID サービスでは、ユーザーの資格情報を保管できる ID ソースとして、以下の 3 つをサポートしています。

アプリケーション開発者が App ID 機能をアプリケーションに組み込むには、その前に、管理者がサービス・インスタンスを作成して ID ソースを追加する必要があります。App ID 機能を (IBM Cloud Directory を利用して) Web アプリに追加するには、以下の手順に従います。

  1. IBM Cloud 内に App ID サービスをセットアップし、新しい IBM クラウド・ディレクトリーを作成します。
  2. そのクラウド・ディレクトリーにユーザーを追加します。以下の図を参照してください。

API セキュリティーを実装する

IoT セキュリティー・デモ・サーバー・アプリケーションのコードから抜粋した以下のスニペットに、IBM App ID を利用してカスタム API エンドポイント (/iotf/devices) をセキュリティーで保護する方法が説明されています。

passport 認証ミドルウェアでは APIStrategy を使用して、着信リクエストを検証します。この検証で調べるのは、リクエストの http ヘッダーに含まれる Authorization フィールドです。App ID での許可ヘッダーは、ホワイト・スペースで区切られた 3 種類のトークンからなります。具体的には、キーワード 'Bearer’、アクセス・トークン、そして省略可能な ID トークンの 3 つです。

const passport = require('passport');
const APIStrategy = require("bluemix-appid").APIStrategy;

app.use(passport.initialize());

passport.use(new APIStrategy());

// Declare the API you want to protect
app.get(iotRouteBase + '/devices',
passport.authenticate(APIStrategy.STRATEGY_NAME, 
{session: true}),
function(req, res) {
		if(error) {
			res.status(400).json(error);
		}
		else {
			res.status(200).json(userGroup.devices);
            }
}
);

クライアント・アプリケーションからは、適切な認証ヘッダーを使用することで、REST API としてのこの保護された API にアクセスできます。以降のセクションで、これらの API を呼び出す Web クライアントとモバイル・クライアントを実装する方法を説明します。

IoT クライアント・アプリケーションをセキュリティーで保護する

IoT アプリケーションをセキュリティーで保護するには、Web アプリケーションとモバイル・アプリケーションの両方に対応する統合認証手法を使用できます。IBM Cloud プラットフォームは、プラットフォーム、データ、アプリケーションの各レベルでセキュリティーを提供します。

図 3 に、App ID サービスに基づく統合認証・許可の手法を示します。統合認証手法を使用する場合、モバイル・アプリケーションと Web アプリケーションが同じ App ID ベースの認証プロバイダーと Cloudant ベースのカスタム認証プロバイダーを使用してデバイス・データを保護し、デバイスにコマンドを送信できるユーザーを制限します。

図 2. 同じ認証、同じセキュアなアプリケーション

Web アプリをセキュリティーで保護する

このセクションでは、ログインしたユーザーのプロファイルに関連付けられた認証・許可に基づいて、Web アプリケーションからセキュリティーで保護された IoT API へのアクセスが可能になる仕組みを見ていきます。

IoT API へのアクセスは、次のステップに従って行われます。

  1. クライアント・プログラムが App ID クライアント・サイド SDK を使用して、IBM App ID インスタンスとのセッションを初期化します。セッションを初期化するために、クライアント・プログラムは App ID インスタンス固有の oauthServerUrl に対応する App ID のテナント ID とクライアント ID、そしてシークレット・キーを提供します。
  2. クライアント・プログラムが LOGIN_URL を使用して App ID とのログイン・セッションを開始します。
  3. App ID がユーザーにログイン・ページを提示します。ユーザーの資格情報が送信されると、App IDはその資格情報を検証し、アクセス・トークンと ID トークンを返します。
  4. クライアント・プログラムが、サーバー上の保護されたエンドポイント (セキュリティー・デモ・サーバー・アプリケーション内では、/iotf/devices) を呼び出します。呼び出し中に、クライアント・プログラムはリクエストに含まれる許可ヘッダーにアクセス・トークンと (場合によっては) ID トークンを設定します。
  5. 保護されたエンドポイント上の passport ミドルウェアとしてセットアップされた App ID サーバー・サイドSDK が、提供されたアクセス・トークンと (存在する場合) ID トークンが有効であるかどうか検証します。
  6. トークンが有効な場合、App ID サーバー・サイド SDK がエンドポイント・ハンドラーの呼び出しを許可します。そうでなければ、レスポンスで HTTP 401 "Unauthorized" を返します。

Implementing the Web Application Authentication Security

IoT セキュリティー・デモ・サーバー・アプリケーションのコードから抜粋した以下のスニペットに、IBM App ID を利用して Web アプリケーションへのログインをセキュリティーで保護する方法が説明されています。

const WebAppStrategy = require("bluemix-appid").WebAppStrategy;

// Configure express application to use passportjs
app.use(passport.initialize());
app.use(passport.session());

const LOGIN_URL = "/ibm/bluemix/appid/login";
const CALLBACK_URL = "/ibm/bluemix/appid/callback";
const LANDING_PAGE_URL = "/IOT_sample_app.html";

// Configure passportjs to use WebAppStrategy
passport.use(new WebAppStrategy({
	tenantId: "*******************",
	clientId: "*******************",
	secret: "*******************",
	oauthServerUrl: "*******************",
	redirectUri: "http://localhost:1234" + CALLBACK_URL
}));

// Explicit login endpoint. Will always redirect browser to login widget.
// If forceLogin is set to false redirect to login widget will not occur 
// for already authenticated users.
app.get(LOGIN_URL, passport.authenticate(WebAppStrategy.STRATEGY_NAME, {
	successRedirect: LANDING_PAGE_URL,
	forceLogin: true
}));

// Callback to finish the authorization process. Will retrieve access and 
// identity tokens from App ID service.
app.get(CALLBACK_URL, passport.authenticate(WebAppStrategy.STRATEGY_NAME));

正常にログインしたユーザーには、そのユーザーに表示することが許可されたデバイスのデータをフェッチするページを表示します。そのために、上記のカスタム Node.js サーバーに含まれている次の 2 つの保護されたカスタム API を呼び出します。

  1. /iotf/devices。これにより、許可されたデバイスのリストを取得します。
  2. /iotf/devices/:deviceid?count=n。これにより、最後の n 件のデバイス・データを取得します (IBM IoT の用語では、デバイス・データは「deviceEvent」と呼ばれます)。

保護された API にアクセスするには、リクエストのヘッダー内で適切に許可トークンを設定する必要があります。Web アプリケーション・サイドのコード (クライアント・サイドのコード) から抜粋した以下のスニペットに、適切な設定が説明されています。

// Protected area. If current user is not authenticated - redirect to the 
// login widget.
// In case user is authenticated - a page with current user information
// will be returned.
app.get("/protected", passport.authenticate(WebAppStrategy.STRATEGY_NAME), 
function(req, res){
	var authContext = req.session[WebAppStrategy.AUTH_CONTEXT];
	var accessToken = authContext.accessToken;
	var identityToken = authContext.identityToken;

	console.log("AUTH_CONTEXT: " + JSON.stringify(authContext), null, '    ');

	var options = {
    	url: 'http://iotsecuritydemo2.mybluemix.net/iotf/devices,
    	headers: {
			'Authorization': 'Bearer '+accessToken+' '+identityToken
    	}};

	request.get(options, function (error, response, body) {
		if(error) {
			console.log(error);
			res.send(error);
		}
		else {
	        	console.log("response - " + response.code);
	        	console.log("body - " + body);	
	         	res.send(body);
	    }
	});

モバイル・アプリをセキュリティーで保護する

IBM App ID サービスを利用して、モバイル・アプリケーションのセキュリティーを確保するサービスを提供することもできます。そのためのフローは、Web アプリケーションをセキュリティーで保護する場合のフローとまったく同じです。

  1. モバイル・デバイスが App ID クライアント・サイド SDK を使用して、IBM App ID の特定のインスタンスとのセッションを初期化します。セッションを初期化するために、モバイル・デバイスは App ID のテナント ID とリージョン ID を提供します。
  2. モバイル・デバイスはこれが匿名ログインであるのか資格情報ベースのログインであるのかを指定して、App ID とのログイン・セッションを開始します。
  3. 匿名ログインの場合、App ID は直ちに該当するアクセス・トークンと ID トークンを返します。資格情報ベースのログインの場合、App ID はユーザーにログイン・ページを表示します。ユーザーの資格情報が送信されると、その資格情報を検証し、アクセス・トークンと ID トークンを返します。
  4. モバイル・デバイスが App ID クライアント・サイド SDK から提供された Request クラスを使用して、モバイル・アプリケーション・バックエンド上の保護されたエンドポイント (セキュリティー・デモ・サーバー・アプリケーションでは、/iotf/devices) を呼び出します。
  5. App ID クライアント・サイド SDK が、キャッシュされた許可ヘッダーをリクエストに追加した上で、エンドポイント上の保護された API を呼び出して、提供されたアクセス・トークンと (存在する場合) ID トークンが有効であるかどうか検証します。
  6. トークンが有効な場合、App ID サーバー・サイド SDK がエンドポイント・ハンドラーの呼び出しを許可します。そうでなければ、レスポンスで HTTP 401 "Unauthorized" を返します。
  7. 認証フローでは、App ID サービスに、認証プロバイダーとして Facebook、Google、または IBM Cloud Directory のどれが構成されているのかを踏まえて、認証結果を App ID サーバー・サイド SDK に返します。
  8. App ID サーバー・サイド SDK に対する認証フローが成功すると、保護されたエンドポイント (セキュリティー・デモ・サーバー・アプリケーション内では、/iotf/devices) のエンドポイント・ハンドラーが呼び出されます。

App ID Client SDK を初期化する (Android の場合)

次のコード・スニペットに、App ID クライアント SDK を初期化する方法が示されています。

テナント ID は、IBM Cloud App ID ダッシュボードの「Service Credentials (サービス資格情報)」セクション内で確認できます。

// Initialize IBM Cloud AppID service SDK with tenant ID and region of the 
// AppID service to connect to
// You can find your tenant ID and region in the Service Credentials section 
//at left hand side of your AppID service dashboard
        appId = AppID.getInstance();

        appId.initialize(
                getApplicationContext(),
                DeviceIoTDemoApplication.IBMCLOUDAPPID_TENANT_ID,
                DeviceIoTDemoApplication.IBMCLOUDAPPID_REGION_ID);

        bmsClient = BMSClient.getInstance();

        bmsClient.initialize(
                getApplicationContext(),
                DeviceIoTDemoApplication.BMSCLIENT_REGION_ID
        );

SDK の初期化が完了したら、ログインが匿名ログインになるのか、それとも特定の資格情報を使用してログインすることになるのか判断してください。ログインを開始するには、以下のコード・スニペットを使用します。

public void startLoginActivity(View view) {

    LoginWidget loginWidget = appId.getLoginWidget();
    // Using persisted access token is optional
    final String storedAccessToken = tokensPersistenceManager.getStoredAccessToken();

    AppIdAuthorizationListener appIdAuthorizationListener =
            new AppIdAuthorizationListener(
                    this,
                    appIDAuthorizationManager,
                    false);

    loginWidget.launch(this, appIdAuthorizationListener);
}

認証プロセスが成功または失敗した時点で、このウィジェットが appIdAuthorizationListener に対するコールバックを行います。

セキュアな API にリクエストを送信する

認証プロセスが成功した場合、保護された API にリクエストを送信できます。

http://<アプリケーション・ルート>/iotf/devices

モバイル・アプリケーションから上記のエンドポイントにリクエストを送信するには、Android 対応の App ID クライアント SDK から提供された Request クラスを使用します。

new Request(
    SERVER_HOSTNAME + "/iotf/devices/",     
    Request.GET).send(
        DeviceIoTDemoApplication.get(), 
        new ResponseListener() {
            @Override
            public void onSuccess(Response response) {
                Log.i("onSuccess(): Authorized devices are "+
                    response.getResponseText());
            }

            @Override
            public void onFailure(Response response, Throwable t, JSONObject extendedInfo) {
                final String errorMessage =
                    (null != response ? response.getResponseText() : "") + "\n" +
                    (null != t ? t.toString() : "") + "\n" +
                    (null != extendedInfo ? extendedInfo.toString() : "") + "\n";

                Log.e(TAG, errorMessage);
            }
        }
    );

Request クラスは、上述のカスタム Node.js サーバー上の保護されたサーバー API を呼び出す際に、App ID サービスから受け取った認証アクセス・トークンおよび ID トークンをリクエストのヘッダーとして渡します。サーバーは APIStrategy を使用して、渡されたトークンを App ID サービスに照合して検証した上で、ビジネス・ロジックを実行します。

サンプル・モバイル Android クライアント

この記事のために開発したモバイル Android クライアントのサンプル・アプリは、最初にログインするようユーザーに求めます。ユーザーは必要に応じて匿名ユーザーとして続行することもできます。

ログインすることを希望するユーザーについては、モバイル・アプリが AppID インスタンスから LoginWidget を取得し、このログイン・ウィジェットに制御を渡します。ログイン・ウィジェットは、モバイル・アプリがユーザーから提供された資格情報に直接アクセスしないよう、ユーザー名とパスワードを収集する Web ベースのログイン・ページを制御します。

この Android アプリは、 AppIdAuthorizationListener というカスタム認証リスナーを実装します。このクラスは、認証の成功、失敗、および同様のイベント発生時に、ログイン・ウィジェットからのコールバック通知を処理します。認証が成功した場合、リスナーはカスタム・メソッド getAuthorizedDevices を実装して、カスタム Node.js サーバー上の保護された /iotf/devices API を呼び出します。

Android スマートフォンの 3 つのスクリーンショット

Android スマートフォンの 3 つのスクリーンショット

認証が成功すると、デバイス API はこのユーザーに表示が許可されているデバイスのリストを返します。これらのデバイスのそれぞれが、アプリ UI の別個のタブに表示されます。各タブに表示される内容は、カスタム Node.js サーバー上の保護された別の API によって取得された、対応するデバイスの最後のイベントです。そのイベントのタイム・スタンプとセンサーのペイロード・データが表示されます。

public class AppIdAuthorizationListener implements AuthorizationListener {

    private static final String TAG = AppIdAuthorizationListener.class.getSimpleName();

    private NoticeHelper noticeHelper;
    private TokensPersistenceManager tokensPersistenceManager;
    private boolean isAnonymous;
    private Activity activity;

    public AppIdAuthorizationListener(Activity activity, AppIDAuthorizationManager authorizationManager, boolean isAnonymous) {
        tokensPersistenceManager = new TokensPersistenceManager(activity, authorizationManager);
        noticeHelper = new NoticeHelper(activity, authorizationManager, tokensPersistenceManager);
        this.isAnonymous = isAnonymous;
        this.activity = activity;
    }

    @Override
    public void onAuthorizationFailure(AuthorizationException exception) {
        Log.e(logTag("onAuthorizationFailure"),"Authorization failed", exception);
    }

    @Override
    public void onAuthorizationCanceled() {
        Log.w(logTag("onAuthorizationCanceled"),"Authorization canceled");
    }

    @Override
    public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken) {
        Log.i(logTag("onAuthorizationSuccess"),"Authorization succeeded");
        if (accessToken == null && identityToken == null) {
            Log.i(logTag("onAuthorizationSuccess"),"Both access and identity tokens are null.");

        } else {
            Log.d(TAG, "Access Token: " + (new Gson()).toJson(accessToken));
            Log.d(TAG, "Identity Token: " + (new Gson()).toJson(identityToken));

            // Execute your success logic here
        }
    }

    private String logTag(String methodName){
        return this.getClass().getCanonicalName() + "." + methodName;
    }
}

この記事でのペイロード・データは、このリンク先のページから入手できるデバイス・シミュレーター・プログラムを使ってシミュレーションできます。

アプリのセキュリティーの脆弱性をスキャンして監視する

IBM Cloud プラットフォームには、アプリをスキャンまたは監視するために利用できるサービスも用意されています。例えば、IBM Application Security on Cloud サービスを利用すると、アプリにセキュリティーの抜け穴がないことを確実化できます。開発者はこれらのサービスを利用して、Web およびモバイル・アプリをデプロイする前に脆弱性をスキャンし、セキュリティー上の問題を識別して、推奨されるフィックスを実装することができます。さらに、App ID サービスに用意されているダッシュボードを使用して、モバイル・アプリの使用状況、そしてデバイス内でのセキュリティー・イベント (認証の成功または失敗など) を監視および分析できます。

まとめ

IoTデバイスから取り込んだ機密データを分析するアプリケーションや、これらの IoT デバイス上の機能を制御するアプリケーションでは、セキュリティーを焦点領域の 1 つにしなければなりません。この記事では、IBM Cloud プラットフォーム上で実行される IoT アプリケーション層のセキュリティーに注目し、IBM Cloud のセキュリティー・サービスを利用して Web アプリとモバイル・アプリに共通のユーザー認証・許可をどのようにして実装するのか、機密データを Cloudant データベースに安全に保管するにはどのようにするのかを説明しました。

謝辞

この記事のレビューと提案で多大な協力をしてくれた IBM Cloud ソリューション・アーキテクトの Subrata Saha と IBM Cloud App ID オファリング・マネージャーの Beery Holstein に感謝の言葉を贈ります。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Internet of Things, セキュリティ
ArticleID=1039190
ArticleTitle=セキュアな IoT ソリューションの設計と構築, 第 3 回: IoT アプリケーションをセキュリティーで保護する
publish-date=10112018