あなたのAlexaダッシュボード 設定

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

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

この文書は、ウェブサービスの開発とホスティングにのみ適用されます。スキルを、AWS Lambda(Amazon Web Servicesのサービスの1つ)のAWS Lambda関数として実装する場合は、代わりに「カスタムスキルのAWS Lambda関数を作成する」を参照してください。

ウェブサービスは、カスタムスキルの実装にのみ使用できます。スマートホームスキルAPIを使用している場合は、Lambda関数としてスキルアダプターをホストする必要があります。

ウェブサービスの要件

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

  1. サービスがインターネットにアクセス可能であること。
  2. サービスがAlexa Skills Kitインターフェースに準拠していること。
  3. サービスが、Amazon信頼済み証明書を活用したSSL/TLS上のHTTPをサポートしていること。
  4. サービスが、ポート443上のリクエストを受け入れること。
  5. サービスが、「subject alternate name」がエンドポイントのドメイン名と一致する証明書を提示すること。
  6. サービスが、受信するリクエストはAlexaからのものであることを検証できること。

Apache HTTP Serverを使用してウェブサービスをホストする場合は、2.4.10以降のバージョンを使用してください。それ以前のバージョンのApache HTTP Serverは、コンフィギュレーションファイルで、サーバーのServerNameまたはServerAliasが設定されていない場合、「認識されない名前」の警告を送信します。これにより、Alexaサービスがカスタマーリクエストをサーバーに送信できなくなります。対処するには、サーバーを2.4.10以降のバージョンにアップグレードするか、ServerName/ ServerAliasをサーバーのコンフィギュレーションファイルに追加します。

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

ウェブサービスに送信されたリクエストは、インターネット経由で送信されます。エンドポイントをセキュリティ攻撃から保護するには、ウェブサービスで、受信するリクエストがAlexaからのものであることを確認する必要があります。他のソースから受信するすべてのリクエストは拒否する必要があります。

受信するリクエストの検証には2つのパートがあります。

  • リクエストの署名を確認し、リクエストが本物であることを確認します。Alexaは、すべてのHTTPSリクエストに署名をします。
    • これは、Alexaスキルの認定およびAmazonユーザーへの公開に必須です。署名のないリクエストを受け入れる、もしくは、リクエストの署名を検証できないウェブサービスは、認定されません。
    • Javaライブラリは、この検証をSpeechletServletクラスで行います。Javaライブラリを使用しない場合、独自に検証を行う必要があります。
    • SpeechletServletクラスを使用しないでJavaライブラリを使用する場合、SpeechletRequestSignatureVerifierクラスを使用することができます。
  • リクエストのタイムスタンプを確認し、リクエストが「リプレイ」攻撃の一環として送信された古いリクエストではないことを確認します。
    • これは、Alexaスキルの認定およびAmazonユーザーへの公開に必須です。
    • Javaライブラリは、この検証をSpeechletServletクラスで行います。システムプロパティcom.amazon.speech.speechlet.servlet.timestampToleranceのトレランスを秒数で指定できるようにする必要があります。
    • SpeechletServletクラスを使用しないでJavaライブラリを使用する場合、TimeStampSpeechletRequestVerifierクラスを使用することができます。

詳細については、以下のセクションを参照してください。

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

Alexaによって送信されたリクエストのHTTPヘッダーには、署名の検証に必要な情報が提供されます。

  • SignatureCertChainUrl
  • Signature

署名を検証するには、以下の手順を実行します。

  1. リクエストのSignatureCertChainUrlヘッダーの値に指定されたURLを検証し、Amazonで使用される形式に一致することを確認します。「署名証明書のURLを検証する」を参照してください。
  2. リクエストのSignatureCertChainUrlヘッダーの値に指定されたURLから、Alexaがメッセージの署名に使用した、PEMエンコードされたX.509証明書チェーンをダウンロードします。

    このチェーンは証明書が定期的に更新されるよう実行時に提供されるため、ウェブサービスはさまざまなコンテンツのさまざまなURLに対応する必要があります。

  3. この証明書チェーンは、以下の順序で構成されています。(1) Amazonが署名する証明書 (2) ルート認証局(CA)証明書への信頼チェーンを作成する1つ以上の追加の証明書。署名する証明書の有効性を確認するには、以下のチェックを実施してください。
    • 署名する証明書の有効期限が切れていないこと(Not BeforeおよびNot Afterの両方の日付を検証)。
    • ドメインecho-api.amazon.comが、署名する証明書のSubject Alternative Names(SAN)セクションにあること。
    • チェーンのすべての証明書が結合されてルートCA証明書の信頼チェーンが作られること。
  4. 署名する証明書が有効であると判断したら、証明書から公開鍵を抽出します。
  5. 暗号化された署名を取得するリクエストのSignatureヘッダーの値をBase64でデコードします。
  6. 署名する証明書から抽出した公開鍵を使用して、暗号化された署名を解読し、アサートされたハッシュ値を生成します。
  7. HTTPSリクエストの全文からSHA-1ハッシュ値を生成し、派生したハッシュ値を生成します。
  8. アサートされたハッシュ値と派生したハッシュ値を比較して、一致することを確認します。

署名証明書のURLを検証する

SignatureCertChainUrlヘッダーに指定されたURLから証明書をダウンロードする前に、そのURLはAmazonが証明書に使用するURLを表していることを確認する必要があります。これにより、ウェブサービスに悪意のあるファイルをダウンロードさせるリクエストなどの攻撃から保護することができます。

まず、URLを正規化し、正しい形式で記述されたURLに照らして検証できるようにします。たとえば、

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

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

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

次に、URLが以下のそれぞれの基準を満たしているかどうかを判断します。

  1. プロトコルがhttpsと等しい(大文字小文字の区別なし)。
  2. ホスト名がs3.amazonaws.comと等しい(大文字小文字の区別なし)。
  3. パスが/echo.api/で始まる(大文字小文字の区別あり)。
  4. 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がこれらの検証にパスしない場合、リクエストを拒否し、署名の検証に進まないでください。

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

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

サービスでは、トレランスを150秒(2分半)以内に設定する必要があります。これにより、サービスは、現在時刻の150秒以内のtimestampを持つリクエストのみを受け付けるようになります。この値より大きいトレランスを設定したウェブサービスは、Amazonカスタマーに公開できません。

Javaライブラリを使用している場合、SpeechletServletクラスがこの検証を処理します。システムプロパティのトレランスを秒数で指定できるようにする必要があります。

com.amazon.speech.speechlet.servlet.timestampTolerance

リクエストのtimestampが、指定したトレランスの範囲を超えている場合、SpeechletServletはウェブサービスのメソッドを一切呼び出さず、代わりにHTTPエラーコード(400 Bad Request)を返します。このプロパティを空にすると、タイムスタンプの検証は実行されません。開発とテストの際には空にできますが、Alexaスキルをユーザーに公開する前に必ず検証を有効にする必要があります。

このシステムプロパティは、ウェブサービスの起動時にJVMに引数を渡すことで設定できます。

  • Launcherクラス(サンプルで使われているLauncher.javaクラスなど)を使用してEclipseでウェブサービスを実行する場合は、以下のように実行コンフィギュレーションにVM引数を追加できます。

    -Dcom.amazon.speech.speechlet.servlet.timestampTolerance=tolerance in seconds

  • Antスクリプトでウェブサービスを開始する場合、スクリプトの<java>タグ内に以下のプロパティを追加します。

     <java classname="Launcher" classpathref="java.sdk.classpath" fork="true">
         <sysproperty key="com.amazon.speech.speechlet.servlet.timestampTolerance"
                      value="tolerance in seconds" />
     </java>
    
  • Elastic Beanstalkでウェブサービスを実行する場合、Elastic Beanstalkのコンソールでプロパティを設定できます。AWS Elastic Beanstalkにカスタムスキルのウェブサービスをデプロイするの「Elastic BeanstalkのJavaシステムプロパティを設定する」を参照してください。

Javaライブラリを使用しない場合、独自に検証を行う必要があります。timestampは、次のように、リクエストのJSON本文のrequestオブジェクトに含まれています。

{
  "version": "1.0",
  "session": {
    "new": boolean,
    ...(additional session properties not shown)
  },
  "request": {
    "type": "LaunchRequest",
    "timestamp": "string",
    "requestId": "string"
  }
}

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

次のステップ