カスタムスキルをウェブサービスとしてホスティングする
クラウド内のAlexaサービスからリクエストを受け付けて応答を返すウェブサービスを実装することにより、Alexa用のカスタムスキルを開発できます。サービスが以下の要件を満たしていれば、どのプログラミング言語を使用しても、ウェブサービスを開発できます。
これらの要件は、カスタムウェブサービスを使用するスキルにのみ適用されます。また、アマゾンウェブサービスが提供するAWS Lambdaを使用して、AWS Lambda関数としてスキルを実装することもできます。詳細については、カスタムスキルをAWS Lambda関数としてホスティングするを参照してください。
ウェブサービスの要件
Alexaから送信されたリクエストを処理するには、ウェブサービスで以下の要件を満たす必要があります。
- サービスがインターネットでアクセス可能であること。
- サービスが、ポート443上のHTTPリクエストを受け入れること。
- サービスが、Amazon信頼済み証明書を使用したSSL/TLS上のHTTPをサポートしていること。ウェブサービスのドメイン名が、証明書の
Subject Alternative Names
(SAN)セクションにあること。テストでは、自己署名証明書を作成できます。詳細については、SSLのオプションについてを参照してください。 - サービスが、受信するリクエストはAlexaからのものであることを検証できること。詳細については、Alexaから送信されたリクエストを検証するを参照してください。
- サービスがAlexa Skills Kitインターフェースに準拠していること。
ServerName
かServerAlias
が設定されていない場合、unrecognized_name
の警告を送信します。これにより、ユーザーがスキルを使用するとき、Alexaサービスがリクエストをサーバーに送信できなくなります。2.4.10以降のバージョンのApache HTTP Serverにアップグレードするか、サーバーの設定ファイルにServerName
またはServerAlias
を追加してください。SSLのオプションについて
Alexaがスキルのウェブサービスと通信するとき、ユーザーのリクエストとそれに対する応答はインターネットで送信されます。Alexaでは、このデータの機密性および保全性を確保するために、必ずSSL/TLSを使ったHTTP接続を使用します。
つまり、ユーザーに公開済みのスキルのウェブサービスは、接続の確立時に有効な信頼できる証明書を提示する必要があります。また、対応する秘密鍵を保持していなければなりません。
ウェブサービスで使用するSSL証明書のタイプを指定する必要があります。証明書のタイプは、Alexa Skills Kit開発者コンソールのビルドページのエンドポイントセクションで指定できます。以下に示すとおり、ウェブサービスで使用しているSSL証明書のタイプに応じて、適切な設定を選択します。どれを選択するかわからない場合は、ウェブサービスで使用する証明書のタイプを決定するために、ホスティングプロバイダーに確認する必要がある場合もあります。
- ウェブサービスでAmazon認定の認証局が署名した証明書を使用している場合は、開発用のエンドポイントには、信頼された証明機関が発行した証明書がありますを選択します。
- ウェブサービスでワイルドカード証明書を使用している場合、開発用のエンドポイントは、証明機関が発行したワイルドカード証明書をもつドメインのサブドメインですを選択します。ワイルドカード証明書は、1つで複数のサブドメインにSSLを提供します。この証明書のタイプは、Amazon認定の認証局が署名した場合のみ使用できます。
-
テストでは、ウェブサービスに自己署名証明書を使用できます。この場合、証明書を自分で作成して、Alexa Skills Kit開発者コンソールにアップロードし、Alexaサービスがウェブサービスに接続する際にその証明書を提示するようにウェブサービスを設定します。詳細については、自己署名証明書を使用するようウェブサービスを設定するを参照してください。
注:自己署名証明書は、テストでのみ使用できます。スキルを公開するには、ウェブサービスでAmazon認定の認証局が署名した証明書を使用する必要があります。
Alexaから送信されたリクエストを検証する
Alexaサービスがウェブサービスに送信したリクエストは、インターネット経由で送信されます。ウェブサービスをセキュリティ攻撃から保護するには、ウェブサービスで、受信するリクエストがAlexaからのものであることを確認する必要があります。Alexa以外から送信されたリクエストは拒否する必要があります。スキルを認定してユーザーに公開するためには、この対応が必須です。署名のないリクエストや期限切れのリクエストを受け付けることができるウェブサービスは、認定されません。
JavaScript、JavaまたはPythonを使用してウェブサービスを開発する場合は、Alexa Skills Kit SDK(ASK SDK)for Node.js、JavaまたはPythonを使用して、ウェブサービスで受信したリクエストがAlexaから送信されていることを検証します。またSDKでは、ウェブサービスを開発するのに役立つコードが提供されます。
SDKを使用したカスタムウェブサービスの開発の詳細については、以下を参照してください。
ASK SDKを使用しない場合は、受信するリクエストを検証するためのコードを記述する必要があります。詳細については、Alexaから送信されたリクエストを手動で検証するを参照してください。
ASK SDK for Node.jsを使用する
ASK SDK for Node.jsは、ask-sdk-express-adapter
パッケージでカスタムウェブサービスを開発するのに役立ちます。このパッケージを使用すると、ウェブサービスで受信したリクエストがAlexaから送信されたものであることを検証できます。
さらにSDKでは、Express.jsの拡張機能が提供されます。このフレームワークは、Node.jsを使用したウェブアプリケーションを開発する際によく使用されています。これらの拡張機能を使用して、スキルのウェブサービスを開発できます。
詳細およびサンプルコードについては、ASK SDK for Node.js技術資料の「 カスタムスキルをウェブサービスとしてホスティングする」を参照してください。
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サービスからのリクエストであることを手動で検証するには、以下の手順を実行するコードを記述する必要があります。
- リクエストの署名を確認し、リクエストが本物であることを確認します。Alexaは、すべてのHTTPSリクエストに署名をします。詳細については、リクエストの署名を確認するを参照してください。
- リクエストのタイムスタンプを確認し、リクエストが「リプレイ」攻撃の一環として送信された古いリクエストではないことを確認します。詳細については、リクエストのタイムスタンプを確認するを参照してください。
400 Bad Request
を含む応答を送信する必要があります。リクエストの署名を確認する
Alexaからウェブサービスに送信されたリクエストには、2つのHTTPヘッダーが含まれています。これを使用して、リクエストの署名を確認する必要があります。
SignatureCertChainUrl
Signature-256
Signature
ヘッダーをHTTPリクエスト本文のSHA-1ハッシュに対して検証している場合、Signature-256
ヘッダーをHTTPリクエスト本文のSHA-256ハッシュに対して検証するよう実装を更新することをお勧めします。リクエストの署名を確認して検証するには:
-
SignatureCertChainUrl
ヘッダーのURLを検証し、Alexaが使用している形式と一致していることを確認します。これにより、ウェブサービスに悪意のあるファイルをダウンロードさせるリクエストの攻撃から保護することができます。-
ドット部分、重複したスラッシュ、フラグメントを削除して、
SignatureCertChainUrl
ヘッダーのURLを正規化します。例として、以下のパスを正規化してみましょう。https://s3.amazonaws.com/echo.api/../echo.api/echo-api-cert.pem
を次のように正規化します。
https://s3.amazonaws.com/echo.api/echo-api-cert.pem
-
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がこれらの条件を満たさない場合、次のステップには進めません。
- プロトコルが
-
-
リクエストの
SignatureCertChainUrl
ヘッダーに指定されたURLを使用して、PEMエンコードされたX.509証明書チェーンをダウンロードします。定期的に更新できるように、このチェーンは実行時に提供されます。ウェブサービスはさまざまなコンテンツのさまざまなURLに対応する必要があります。 - 前のステップでダウンロードした証明書チェーンは、以下の順序で構成されています。
- Amazonが署名する証明書
- 認証局(CA)のルート証明書への信頼チェーンを作成する1つ以上の追加の証明書
署名する証明書の有効性を確認するには、以下の手順を行ってください。
Not Before
およびNot After
の日付を検証し、署名する証明書の有効期限が切れていないことを確認します。echo-api.amazon.com
というドメイン名が、署名する証明書のSubject Alternative Names
(SAN)セクションにあることを確認します。- チェーンのすべての証明書が結合されてルートCA証明書の信頼チェーンが作られていることを検証します。
-
署名する証明書が有効であると確認したら、証明書から公開鍵を抽出します。
-
暗号化された署名を取得するリクエストの
Signature-256
ヘッダーの値をBase64で復号します。 -
署名する証明書から抽出した公開鍵を使用して、暗号化された署名を解読し、アサートされたハッシュ値を生成します。
-
HTTPリクエストの全文からSHA-256ハッシュ値を生成し、派生したハッシュ値を生成します。
- アサートされたハッシュ値と派生したハッシュ値を比較して、一致することを確認します。一致しなかった場合、そのリクエストを破棄します。
リクエストのタイムスタンプを確認する
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
がトレランスの範囲外にあるリクエストを拒否します。
関連トピック
最終更新日: 2023 年 01 月 27 日