カスタムスキルをウェブサービスとしてホスティングする



カスタムスキルをウェブサービスとしてホスティングする

クラウド内のAlexaサービスからリクエストを受け付けて応答を返すウェブサービスを実装することにより、Alexa用のカスタムスキルを開発できます。サービスが以下の要件を満たしていれば、どのプログラミング言語を使用しても、ウェブサービスを開発できます。

これらの要件は、カスタムウェブサービスを使用するスキルにのみ適用されます。また、アマゾンウェブサービスが提供するAWS Lambdaを使用して、AWS Lambda関数としてスキルを実装することもできます。詳細については、カスタムスキルをAWS Lambda関数としてホスティングするを参照してください。

ウェブサービスの要件

Alexaから送信されたリクエストを処理するには、ウェブサービスで以下の要件を満たす必要があります。

  1. サービスがインターネットでアクセス可能であること。
  2. サービスが、ポート443上のHTTPリクエストを受け入れること。
  3. サービスが、Amazon信頼済み証明書を使用したSSL/TLS上のHTTPをサポートしていること。ウェブサービスのドメイン名が、証明書のSubject Alternative Names(SAN)セクションにあること。テストでは、自己署名証明書を作成できます。詳細については、SSLのオプションについてを参照してください。
  4. サービスが、受信するリクエストはAlexaからのものであることを検証できること。詳細については、Alexaから送信されたリクエストを検証するを参照してください。
  5. サービスがAlexa Skills Kitインターフェースに準拠していること。

SSLのオプションについて

Alexaがスキルのウェブサービスと通信するとき、ユーザーのリクエストとそれに対する応答はインターネットで送信されます。Alexaでは、このデータの機密性および保全性を確保するために、必ずSSL/TLSを使ったHTTP接続を使用します。

つまり、ユーザーに公開済みのスキルのウェブサービスは、接続の確立時に有効な信頼できる証明書を提示する必要があります。また、対応する秘密鍵を保持していなければなりません。

ウェブサービスで使用するSSL証明書のタイプを指定する必要があります。証明書のタイプは、Alexa Skills Kit開発者コンソールビルドページエンドポイントセクションで指定できます。以下に示すとおり、ウェブサービスで使用しているSSL証明書のタイプに応じて、適切な設定を選択します。どれを選択するかわからない場合は、ウェブサービスで使用する証明書のタイプを決定するために、ホスティングプロバイダーに確認する必要がある場合もあります。

  • ウェブサービスでAmazon認定の認証局が署名した証明書を使用している場合は、開発用のエンドポイントには、信頼された証明機関が発行した証明書がありますを選択します。
  • ウェブサービスでワイルドカード証明書を使用している場合、開発用のエンドポイントは、証明機関が発行したワイルドカード証明書をもつドメインのサブドメインですを選択します。ワイルドカード証明書は、1つで複数のサブドメインにSSLを提供します。この証明書のタイプは、Amazon認定の認証局が署名した場合のみ使用できます。
  • テストでは、ウェブサービスに自己署名証明書を使用できます。この場合、証明書を自分で作成して、Alexa Skills Kit開発者コンソールにアップロードし、Alexaサービスがウェブサービスに接続する際にその証明書を提示するようにウェブサービスを設定します。詳細については、自己署名証明書を使用するようウェブサービスを設定するを参照してください。

Alexaから送信されたリクエストを検証する

Alexaサービスがウェブサービスに送信したリクエストは、インターネット経由で送信されます。ウェブサービスをセキュリティ攻撃から保護するには、ウェブサービスで、受信するリクエストがAlexaからのものであることを確認する必要があります。Alexa以外から送信されたリクエストは拒否する必要があります。スキルを認定してユーザーに公開するためには、この対応が必須です。署名のないリクエストや期限切れのリクエストを受け付けることができるウェブサービスは、認定されません。

JavaまたはPythonを使用してウェブサービスを開発する場合は、Alexa Skills Kit SDK(ASK SDK)for JavaまたはASK SDK for Pythonを使用して、ウェブサービスで受信したリクエストがAlexaから送信されていることを検証します。またSDKでは、ウェブサービスを開発するのに役立つコードがJavaまたはPythonで提供されます。

SDKを使用したカスタムウェブサービスの開発の詳細については、以下を参照してください。

ASK SDKを使用しない場合は、受信するリクエストを検証するためのコードを記述する必要があります。詳細については、Alexaから送信されたリクエストを手動で検証するを参照してください。

ASK SDK for Javaを使用する

ASK SDK for Javaは、Javaサーブレット形式でカスタムウェブサービスを開発するのに役立ちます。Javaを使用してウェブサービスを開発するが、サーブレットを使用したくない場合でも、SDKを使用して、ウェブサービスで受信したリクエストがAlexaから送信されたものであることを検証することができます。

詳細およびサンプルコードについては、ASK SDK for Java技術資料の「 カスタムスキルをウェブサービスとしてホスティングする」を参照してください。

ASK SDK for Pythonを使用する

ASK SDK for Pythonは、ask-sdk-webservice-supportパッケージでカスタムウェブサービスを開発するのに役立ちます。このパッケージを使用すると、ウェブサービスで受信したリクエストがAlexaから送信されたものであることを検証できます。

さらにSDKでは、FlaskとDjangoの拡張機能が提供されます。この2つのフレームワークは、Pythonを使用したウェブアプリケーションを開発する際によく使用されています。これらの拡張機能を使用して、スキルのウェブサービスを開発できます。

詳細およびサンプルコードについては、ASK SDK for Python技術資料の「カスタムスキルをウェブサービスとしてホスティングする」を参照してください。

Alexaから送信されたリクエストを手動で検証する

Alexaサービスからのリクエストであることを手動で検証するには、以下の手順を実行するコードを記述する必要があります。

  1. リクエストの署名を確認し、リクエストが本物であることを確認します。Alexaは、すべてのHTTPSリクエストに署名をします。詳細については、リクエストの署名を確認するを参照してください。
  2. リクエストのタイムスタンプを確認し、リクエストが「リプレイ」攻撃の一環として送信された古いリクエストではないことを確認します。詳細については、リクエストのタイムスタンプを確認するを参照してください。

リクエストの署名を確認する

Alexaからウェブサービスに送信されたリクエストには、2つのHTTPヘッダーが含まれています。これを使用して、リクエストの署名を確認する必要があります。

  • SignatureCertChainUrl
  • Signature

リクエストの署名を確認して検証するには:

  1. SignatureCertChainUrlヘッダーのURLを検証し、Alexaが使用している形式と一致しているかどうかを確認します。これにより、ウェブサービスに悪意のあるファイルをダウンロードさせるリクエストの攻撃から保護することができます。

    1. ドット部分、重複したスラッシュ、フラグメントを削除して、SignatureCertChainUrlヘッダーのURLを正規化します。例として、以下のパスを正規化してみましょう。

      https://s3.amazonaws.com/echo.api/../echo.api/echo-api-cert.pem
      

      を次のように正規化します。

      https://s3.amazonaws.com/echo.api/echo-api-cert.pem
      
    2. URLが、以下のすべての条件を満たしていることを確認します。

      • プロトコルがhttpsであること(大文字小文字の区別なし)。
      • ホスト名がs3.amazonaws.comであること(大文字小文字の区別なし)。
      • パスが/echo.api/で始まること(大文字小文字の区別あり)。
      • URLにポートが定義されている場合、ポートが443であること。

      以下に、正しい形式で記述されたURLの例を示します。

      • https://s3.amazonaws.com/echo.api/echo-api-cert.pem
      • https://s3.amazonaws.com:443/echo.api/echo-api-cert.pem
      • https://s3.amazonaws.com/echo.api/../echo.api/echo-api-cert.pem

      以下に、無効なURLの例を示します。

      • http://s3.amazonaws.com/echo.api/echo-api-cert.pem(無効なプロトコル)
      • https://notamazon.com/echo.api/echo-api-cert.pem(無効なホスト名)
      • https://s3.amazonaws.com/EcHo.aPi/echo-api-cert.pem(無効なパス)
      • https://s3.amazonaws.com/invalid.path/echo-api-cert.pem(無効なパス)
      • https://s3.amazonaws.com:563/echo.api/echo-api-cert.pem(無効なポート)

      URLがこれらの条件を満たさない場合、次のステップには進めません。

  2. リクエストのSignatureCertChainUrlヘッダーに指定されたURLを使用して、PEMエンコードされたX.509証明書チェーンをダウンロードします。定期的に更新できるように、このチェーンは実行時に提供されます。ウェブサービスはさまざまなコンテンツのさまざまなURLに対応する必要があります。

  3. 前のステップでダウンロードした証明書チェーンは、以下の順序で構成されています。
    • Amazonが署名する証明書
    • 認証局(CA)のルート証明書への信頼チェーンを作成する1つ以上の追加の証明書

    署名する証明書の有効性を確認するには、以下の手順を行ってください。

    1. Not BeforeおよびNot Afterの日付を検証し、署名する証明書の有効期限が切れていないことを確認します。
    2. echo-api.amazon.comというドメイン名が、署名する証明書のSubject Alternative Names(SAN)セクションにあることを確認します。
    3. チェーンのすべての証明書が結合されてルートCA証明書の信頼チェーンが作られていることを検証します。
  4. 署名する証明書が有効であると確認したら、証明書から公開鍵を抽出します。

  5. 暗号化された署名を取得するリクエストのSignatureヘッダーの値をBase64で複合化します。

  6. 署名する証明書から抽出した公開鍵を使用して、暗号化された署名を解読し、アサートされたハッシュ値を生成します。

  7. HTTPリクエストの全文からSHA-1ハッシュ値を生成し、派生したハッシュ値を生成します。

  8. アサートされたハッシュ値と派生したハッシュ値を比較して、一致することを確認します。一致しなかった場合、そのリクエストを破棄します。

リクエストのタイムスタンプを確認する

Alexaからウェブサービスに送信されるすべてのリクエストの本文には、タイムスタンプが含まれます。このタイムスタンプは、リクエストの署名の一部であり、変更はできません。また変更するとリクエストの署名が無効になります。このタイムスタンプを使用すると、応答する前にリクエストが最新であることを確認できます。「リプレイ」攻撃(攻撃者が正規に署名されたリクエストを取得して繰り返し再送することによりウェブサービスを停止させる攻撃)からウェブサービスを保護できます。

ウェブサービスでは、トレランスを150秒(2分半)以内に設定する必要があります。これにより、サービスは、現在時刻から150秒以内のtimestampを持つリクエストのみを処理するようになります。timestampが現在時刻から150秒を超えている場合、そのリクエストを破棄します。ウェブサービスが、現在時刻と一致せず150秒を超えているリクエストを処理すると、スキルが認定されず、ユーザーに公開されません。

timestampは、次に示すように、リクエストのJSON本文のrequestオブジェクトに含まれています。次に例を示します:

{
  "version": "1.0",
  "session": {
    "new": true,
    ...
  },
  "request": {
    "type": "LaunchRequest",
    "timestamp": "string",
    "requestId": "string"
  }
}

timestampの値は、ISO 8601形式の文字列(2019-05-13T12:34:56Z)で指定する必要があります。コードで文字列をdateオブジェクトに変換し、ウェブサービスが許容するトレランスの範囲内(現在時刻から150秒以内)であることを確認する必要があります。HTTPエラーコード(400 Bad Requestなど)を使用して、timestampがトレランスの範囲外にあるリクエストを拒否します。