多要素認証のキーとして、LTE-Mボタンを使ってみた

多要素認証のキーとして、LTE-Mボタンを使ってみた:


はじめに

これは、SORACOM Technology Camp 2018のナイトイベントLTで発表した内容を、ハンズオン風味で追体験が出来るように記事化したものです。

  【スライド】 もういい加減、パスワード使うの止めにしません?

内容は、SORACOM LTE-M Button (あのボタン)を使って、多要素認証の可能性を実証したものです。

一つ目の認証キーとしてユニークなIDとなるお客様番号を、二つ目の認証キーとしてあのボタンを使っています。

実際に複数のブラウザで試してみた様子がコチラです。

  【動画】 多要素認証のキーとして、LTE-Mボタンを使ってみた(音声は流れません)

  

多要素認証のキーとして、LTE-Mボタンを使ってみた


全体の構成は、次のようになっています。

(以下、記事に張り付けている全ての画像は、クリックすると等倍に拡大して表示できます)

  

68747470733a2f2f71696974612d696d6167652d



今回使ったもの

  • SORACOM LTE-M Button powered by AWS
  • Visual Studio 2017


C#でLambdaを書くために必要なこと

C#でLambdaを扱ったことがない方は、事前に準備が必要です。

こちらに解りやすい記事がありますので、先に一通り実践されることをオススメします。

 AWS Lambda関数をC#で書いて実行するまで


AWSでやること


Lambda関数を作る

AWSマネジメントコンソールから「Lambda」を選択して、左側ペインから①の「関数」を選び、②の「関数の作成」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


次の画面に遷移しますので、③の「一から作成」を選択し、④に適当な名前(当記事では"button-login")を入力、⑤のランタイムで「.NET Core 2.1 (C#/PowerShell)」を選択、⑥のロールではドロップダウンボタンを押してリストを表示させた後で、⑦で「カスタムロールの作成」を選択します。

  

68747470733a2f2f71696974612d696d6167652d


すると次の画面が別のタブとして開きますので、IAM ロールが「lambda_basic_execution」となっていることを確認して、⑧の「許可」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


⑨名前、⑩ランタイム、⑪ロール、⑫既存のロール、が次のように全て埋まっていることを確認して、⑬の「関数の作成」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


次の画面のように、正常に作成されましたのメッセージが表示されたら、関数の作成は無事完了です。

  68747470733a2f2f71696974612d696d6167652d


あのボタンを登録する

AWSマネジメントコンソールから「IoT 1-Click」を選択して、①の左側ペインから「オンボード」を選び、②の「デバイスの登録」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


③の「登録コードまたは登録するデバイスの ID」にあのボタンのDSN(DeviceSerialNumber)を入力して、④の「登録」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


ちなみにDSNは、あのボタンのリアカバーを開けると確認できます。

  

68747470733a2f2f71696974612d696d6167652d


次の画面が表示されたら、あのボタンに電池を入れて一回クリックします。

  

68747470733a2f2f71696974612d696d6167652d


10秒程で次の画面に変わりますので、⑤の「完了」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


すると次の画面(管理→デバイス)に自動的に戻りますので、設定したデバイスIDの列中にある⑥「・・・」をクリックします。

ちなみに「デバイスリージョン」はAWS側で自動的に割り振られるため、任意で指定することは出来ません。

  

68747470733a2f2f71696974612d696d6167652d


⑦の「デバイスの有効化」を選択します。

  

68747470733a2f2f71696974612d696d6167652d


これで、あのボタンの登録が完了しました。

画面に表示されているデバイスIDは、後でSORACOMユーザーコンソールからデバイス登録する時に使いますので、控えておいてください。

  

68747470733a2f2f71696974612d696d6167652d



プロジェクトを作る

左側のペインから、①の「管理 → プロジェクト」を選び、②の「プロジェクトの作成」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


③に任意の「プロジェクト名」(当記事では"login-portal")を入力して、④の「次へ」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


次の画面に替わりましたら、⑤の「開始」をクリックします。

  

68747470733a2f2f71696974612d696d6167652d


⑥の「すべてのボタンタイプ」をクリックします。

  

68747470733a2f2f71696974612d696d6167652d


画面が遷移すると、オレンジ色の文字で名前が必要ですと表示されていますので、⑦に任意の「デバイステンプレート名」を入力、⑧のアクションに「Lambda関数の選択」を選択、⑨のAWSリージョンはLambda関数を作るの項で設定したリージョン(当記事では"東京")を選択、⑩で同じくその時に設定したLambda関数の名前(当記事では"button-login")を入力します。

⑪の属性の名前は「customer_code」を入力、⑫のデフォルト値に「0」を入力して、⑬の「プロジェクトの作成」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


次の画面が表示されたら、プロジェクトの作成は成功です。

  

68747470733a2f2f71696974612d696d6167652d



プレイスメントを作る

プレイスメントとは、ボタン毎に固有に設定できるタグのようなものです。

今回は、ここに生のお客様番号を設定します。

AWSマネジメントコンソールから「IoT 1-Click」を選択して、左側のペインから①の「管理 → プロジェクト」を選び、②の名前(当記事では"login-portal")部分をクリックします。

  

68747470733a2f2f71696974612d696d6167652d


次の画面に替わりましたら、③の「プレイスメント」を選択し、④の「プレイスメントの作成」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


更に画面が替わりますので、必要な項目を入力していきます。

まずは⑤に適当な「デバイスのプレイスメント名」を入力します。

次に⑥の「デバイスの選択」をクリックすると、先程登録したあのボタンのDSNが現れますので、その右側にある「選択」をクリックします。

そして⑦の「customer_code」にはデフォルト値の「0」が設定されていますので、適当なお客様番号(最大9桁まで)を入力して上書きします。お客様番号はこの後何度も使いますので、とりあえず覚えやすい番号(当記事では"100")にしておくことをオススメします。

  

68747470733a2f2f71696974612d696d6167652d


全ての入力が問題なく完了しますと、⑧の「プレイスメントの作成」ボタンが押せるようになりますので、そのままクリックします。

  

68747470733a2f2f71696974612d696d6167652d


次の画面が表示されたら、プレイスメントの作成は成功です。

  

68747470733a2f2f71696974612d696d6167652d



SORACOMでやること

以下の手順を端折ったままの状態で1500回クリックしたボタンは見事に文鎮化しますので、末永く使いたい方は要注意です。


デバイスの登録

SORACOMユーザーコンソールから、画面左上にある「Menu」ボタンを押して「ガジェット → Buttons」を選択します。

すると次の画面が表示されますので、①の「+デバイス登録」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


ウィンドウが開きますので、既に控えてあるデバイスIDを②の「製造番号」に入力して、③の「登録」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


次の画面のように、該当のデバイスIDが追加されていたら成功です。

  

68747470733a2f2f71696974612d696d6167652d



Visual Studio でやること

ここからは AWS Toolkit for Visual Studio のインストールが完了していることが前提ですので、ご注意ください。

詳しくは、次の記事をご参照ください。

 AWS Lambda関数をC#で書いて実行するまで


Visual Studio プロジェクトの作成

Lambda関数をデプロイするための「新しいプロジェクト」を「ファイル → 新規作成 → プロジェクト」の手順で作成します。

①左側のペインから「Visual C# → AWS Lambda」を選び、②右側のペインで「AWS Lambda Project (.NET core)」を選択、③Visual Studio プロジェクトの名前を設定して(当記事では"AWSLambda1")、④「OK」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


自動的にNew AWS Lambda C# Project のウィンドウが開きますので、⑤「Empty Function」を選択して、⑥「Finish」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d



コードの入れ換え

ソリューション エクスプローラーでFunction.csを開くと、次のコードが自動的に生成されているのが確認できます。

Function.cs
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
 
using Amazon.Lambda.Core; 
 
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] 
 
namespace AWSLambda1 
{ 
    public class Function 
    { 
 
        /// <summary> 
        /// A simple function that takes a string and does a ToUpper 
        /// </summary> 
        /// <param name="input"></param> 
        /// <param name="context"></param> 
        /// <returns></returns> 
        public string FunctionHandler(string input, ILambdaContext context) 
        { 
            return input?.ToUpper(); 
        } 
    } 
} 
上記のコードFunction.csの中身を、まるごと下記のコードと入れ替えます。

Function.cs
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using System.Net.Http; 
using System.Text; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Linq; 
 
using Amazon.Lambda.Core; 
 
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] 
 
namespace AWSLambda1 
{ 
    public class Function 
    { 
        private static HttpClient client = new HttpClient(); 
 
 
        /// Lambdaから呼ばれるメソッド 
        public string FunctionHandler(JObject request, ILambdaContext context) 
        { 
            bool isSuccess = false; 
            int customerCode = (int)(request["placementInfo"]["attributes"]["customer_code"]);  // 予め placementInfo → attributes → customer_code に設定済みの「お客様番号」をHash化 
 
            // Azure上にある別のWebサービス(Login Portal)にアクセス 
            string hashCode = GetHashCode(customerCode); 
            string url = "https://loginto.azurewebsites.net/ThatButton/" + hashCode; 
            string json = client.GetStringAsync(url).Result; 
 
            // 応答(Json)の解析 
            var response = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);     // 単純な構造のため、KeyValue(Dictionary型)で応答をデシリアライズ 
            if (response.ContainsKey("isSuccess"))                                              // 成否判定用のステータス"isSuccess"が(無事に)含まれているか? 
            { 
                isSuccess = Convert.ToBoolean(response["isSuccess"]); 
            } 
            return isSuccess.ToString();                                                        // ログインの成否 (成功="True" or 失敗="False") 
        } 
 
 
        /// 引数をSHA-1でHash化して返すメソッド 
        private string GetHashCode(int customerCode) 
        { 
            System.Security.Cryptography.HashAlgorithm ha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider(); 
            byte[] hash = ha1.ComputeHash(Encoding.UTF8.GetBytes(customerCode.ToString())); 
            return BitConverter.ToString(hash); 
        } 
    } 
} 
このコードでは、既にプレイスメントで設定済みのお客様番号customer_codeの数字をSHA-1でハッシュ化します。

次にその文字列を、loginto.azurewebsites.net/ThatButton/の後ろにクエリとして付加してから、URLとしてGETします。

例えば、customer_codeに「100」を設定している場合のURLは次の通りです。

  https://loginto.azurewebsites.net/ThatButton/310B86E0B62B828562FC91C7BE5380A992B2786A

ちなみに、他の言語でも同様のロジックでLambda関数を記述すれば、後でご紹介するログインポータル 実験サイトから実際に試して頂くことが可能です。

※ サクッとSHA-1のハッシュ値を調べたい場合は、次のサイトが便利です。

  SHA2/SHA1/MD5ハッシュ生成(Hash Generator)


デプロイ

さて、Function.csの入れ替えが完了しましたら、いよいよLambdaへデプロイしてみます。

ソリューション エクスプローラーでプロジェクトの名前を右クリックして、「Publish to AWS Lambda…」を選びます。

  

68747470733a2f2f71696974612d696d6167652d


すると次のウィンドウが開きますので、「Region:」表示が実際にLambda関数を作ったリージョンと同じかどうかを確認しつつ、①「Function Name:」で作成済みのLambda関数の名前(当記事では"button-login")を選択し、②「Next」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


③「Role Name:」のドロップダウンボタンを押してリストを表示させ、その中の④「Exisiting IAM Roles → lambda_basic_execution」を選択し、⑤「Upload」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


  
68747470733a2f2f71696974612d696d6167652d


しばし待ちます。

  

68747470733a2f2f71696974612d696d6167652d


完了すると、次の画面が表示されます。

デプロイの成否を確認するには、「Sample Input ペイン」の①に下記のJSON(貼り付ける.js)をコピペして、②の「Invoke」ボタンを押します。

  

68747470733a2f2f71696974612d696d6167652d


(貼り付けるJSONはコレです)

貼り付ける.js
{  
    "deviceInfo": {  
        "deviceId": "XXXXXXXXXXXXXXXX",  
        "type": "button",  
        "remainingLife": 99.933334,  
        "attributes": {  
            "projectRegion": "ap-northeast-1",  
            "projectName": "projectName",  
            "placementName": "placementName",  
            "deviceTemplateName": "deviceTemplateName"  
        }  
    },  
    "deviceEvent": {  
        "buttonClicked": {  
            "clickType": "SINGLE",  
            "reportedTime": "2018-11-05T04:29:01.950Z"  
        }  
    },  
 
    "placementInfo": {  
        "projectName": "projectName",  
        "placementName": "ButtonName",  
        "attributes": {  
            "customer_code": "100"  
        },  
        "devices": {  
            "deviceTemplateName": "XXXXXXXXXXXXXXXX"  
        }  
    }  
}  
その結果、③の「Responseペイン」に "False" が帰ってきたら成功です。

ちなみに初回の起動時のみ、Lambda関数が動き出すまで若干の待ち時間があります。

※ もし、エラーメッセージ "errorMessage": "Unable to load type …" が返ってくる場合は、Visual Studio プロジェクトの名前ソースコードのnamespaceが同じかどうかを確認してみてください。


試してみる!

ここまで問題なく完了しましたら、次のWebサイトにアクセスして、実際の挙動を試してみることが出来ます。

  ログインポータル 実験サイト   

68747470733a2f2f71696974612d696d6167652d


Webサイトの使い方は、プレイスメントの項で設定したお客様番号を入力してログインボタンを押すだけです。

詳しくは、記事冒頭のYouTube動画をご覧くださいませ :grin:

※ こちらは無料のホスティングプランを使っているため、初回の起動がヒジョーに遅い場合があります <(_ _)>


まとめ

今回の仕組みのキモは、いついかなる時でも一対一でしか繋がらないことをロジックで保証しているところです。

また、一旦認証が完了した後のページ間のやり取りには、ハッシュ化したお客様番号に紐付くワンタイムのGUIDが振り出され、それをURLのクエリ文字列として用いることで、更なるセキュリティを担保しています。

当記事ではURLを短く表現したいがためにSHA-1を使いましたが、その強度に問題があるため利用に関しては注意が必要です。

また、AWSとAzure間の接続にはSSL(TLS)を使っていますが、更にVPNを使うなどの配慮が要るかもしれません。

当記事は既に長文となってしまいましたので、認証の内部的な仕組み(特にAzureの部分)については、また別の機会に紹介させていただければと思います。


参考

SORACOM公式:

 SORACOM LTE-M Button powered by AWS ユーザーガイド

 SORACOM LTE-M Button powered by AWS をソラコムのガジェット管理に登録する

 SORACOM LTE-M Button の始め方

 SORACOM LTE-M Button powered by AWS を用いた開発 TIPS

 SORACOM LTE-M Button powered by AWS をクリックしてSlackに通知する

AWS公式:

 AWS IoT 1-Click – Lambda 関数のトリガーにシンプルなデバイスを使用する

その他:

 Visual Studio for Mac で AWS Lambda(C#)ファンクションを作成してみた

 AWS Lambda関数をC#で書いて実行するまで

  ↑ これがなければLambda周りでハマっていたと思います。ありがとうございます ;)

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)