ボクココ

個人開発に関するテックブログ

Twilio 録音セキュリティの考察と実装

ども、@kimhiom です。

f:id:cevid_cpp:20211221164707j:plain

この記事は Twilio Advent Calendar 2021 23日目の記事となります。他のも是非みていただければと〜。

近年は セキュリティに関して多くの方々が意識するようになり、私にとって Twilio での録音ファイルをどのように管理するのかについて、最適解を考え続けた。そこでの対応や実装について記そう。

録音をしない、保存しない

まず録音セキュリティを話す前に、録音セキュリティをものすごく気にする方には、そもそも録音をしない を絶賛推奨しよう。ことの発端は全て録音をするから始まるのである。さらに、録音をするだけで Twilio ポイントが引かれるし、その録音ファイルを所持するだけで毎月費用が発生してしまう(ある程度までは無料だけど)。

また、録音を一度ダウンロードして、どこかセキュア?な環境へ保存したら、Twilio 側の録音を削除するという運用で、一般公開を防ぐことが可能だ。ただ、手動での対応は手間がかかりすぎるので、TwiML での Twilio Action で指定した URL 側のプログラム実装すれば自動化できる。ただ、そのローカルな環境で保存したところで、誰がその録音にアクセスできるのかなどの課題は残り続ける。

まず前提を考慮した上で、"ネット上で録音を聞きたい。でもセキュリティをなんとかして" という要望に対して、以下の方法を紹介していこう。

Twilio 提供の 録音セキュリティ

まず、Twilio がデフォルトで提供している録音セキュリティに関してまとめてみる。

1. 予測不可能な録音URL

Twilio で 録音を on にして通話をすると、以下のような形式の URL で録音が再生できるようになる。

https://api.twilio.com/2010-04-01/Accounts/AC****************/Recordings/RE*********************

デフォルトの制限なし録音 URL は、その録音 URL を 社内チャットで共有したり、CRM 側でその録音 URL を保存することで、他の担当者も簡単にその録音が再生できるメリットがある。これは、シンプルに HTML で <audio controls src="https://api.twilio.com/2010-04-01/Accounts/AC****************/Recordings/RE*********************.wav"></audio> と記載するだけで再生が可能だ。

録音は上記の形式で、 ******* の部分が予測困難な文字列になっている。そのため、その録音 URL を知っている誰かが意図的に録音 URL を公開しない限りは、意図しない誰かにアクセスされるリスクは低いと言える。

しかし、逆を言えば、誰かが録音 URL を SNS などでシェアしてしまえば、誰でも再生ができてしまうという問題がある。

2. Basic認証

より再生できる人を限定するために Basic 認証が提供されている。ここでの Basic 認証では、 Twilio Account SID, Twilio AuthToken の2つが必要となる。

つまり、再生には https://{AccountSID}:{AuthToken}@api.twilio.com/2010-04-01/Accounts/AC****************/Recordings/RE********************* といった形式が必要となる。

・・・。なんということでしょう。もしこの URL を誰かがシェアしてしまうと、Twilio API の操作がなんでもできる AccountSID と AuthToken が知られてしまう。録音URL をシェアしなかったとしても、録音を聞こうとする人は必ず AccountSID と AuthToken を知ってそれを入力する必要があるのだけど、この2つのトークンは Twilio 情報の中で最も知られてはいけないトークンだ。よくわかってない担当者が、それをコピペして録音を聞くみたいな運用は絶対に避けたほうがいいだろう。

つまり、この Basic 認証だけで使うべきではない。Twilio ドキュメント側にも、"HTTP認証を暗号化と組み合わせて使うことを強くお薦めします。より詳しい情報はベーシック認証とダイジェスト認証や現在お使いのウェブサーバーのドキュメントをご覧ください。" との記載がある。

3. 録音の Encryption

そこで、録音の暗号化の機能が提供されている。Twilio 側では 暗号化されたファイルが保存され、その録音アクセスには特定のパラメータで Twilio へリクエストを送り、それが正しい場合に録音を複合できるようになる。詳細は以下。

Security | Twilio

メリット

  • 録音を聞けるのは特定の暗号文字列を知っている場合のみ。
  • 実装が必要なので、その実装済みの Web サーバーや スクリプトからに限定される。

デメリット

  • 上記の録音再生環境からでしか、録音が聞けない(これはメリットでもある)
  • Twilio に録音を保存し続ける必要がある(コスト)

録音の独自セキュリティ化

さて、Twilio 標準から抜けて、できる限りデメリットを減らす方向を考えていきたくなってきた。どのように実装していったかを記していく。

まず、TwiML 指定の ActionURL へ録音 URL が飛んできたら、以下のような処理を実施していく。

  1. Twilio 録音をダウンロード
  2. S3 へアップロード
  3. ダウンロードした録音を削除
  4. Twilio 録音削除 API で Twilio 録音を削除

これで、自前 S3 へ録音ファイルを保存して、予測できない録音 URL からアクセスできるようにすれば、録音再生ができるような状態になる。これだけで、例えば録音URL を使って音声文字化したり、感情を取得 API を呼んでみたりすることができる。

さて、以降は Twilio とはほとんど関係ない Amazon S3 部分であることに注意してほしい。

最終ゴール: S3 側で付与された特定パラメータ付きの URL からのみアクセスできる。その URL は、指定秒後に期限が切れる ようにする

今回の実装での強みは、何より時間制限があるということである。特別に付与された URL を生成しない限りは、誰もが録音を聞くことができない。仮に録音 URL を意図せずシェアされたとしても、それにアクセスして聞けるのは 指定した秒数のみ。それ以降は誰も聞けなくなる。録音をクリックした瞬間に再生をするようにすれば、もはや30秒でも問題ないだろう。最初の再生さえできれば、残りの音声ロードは問題なく読み込まれるからである。

ではどんな形で実装していくか。S3 の機能として、S3 バケットポリシー というものがあり、これを使っていく。

参考: バケットポリシーの例 - Amazon Simple Storage Service

バケットポリシーを使うことで、"特定のパラメータが正しく追加付与された URL でないと、S3 の特定ファイルにアクセスできない" 設定をする。

このポリシーの書き方はそれぞれ違うと思うので、ぜひ苦戦しながら設定をしてみていただければ幸いだ。ものすごく大雑把に書くと、以下のような形である。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny", "Principal": "*", "Action": "s3:GetObject",
      "Resource": [
        "arn:aws:s3:::my-twilio-s3/records/*"
      ],
      "Condition": {
        "StringNotEquals": { "アクセス拒否する条件をここに記載" }
      }
    }
  ]
}

S3 にアクセス制限をかけたら、そのアクセス制限を回避するための録音 URL を生成する必要がある。Presigned URL というものだ。 この生成には、自前サーバーから 取得したい S3 のバケットとキーを指定し、AWS へリクエスト。そのレスポンスで返ってくる録音 URL を返す流れとなる。

参考 AWS Ruby Class: Aws::S3::Presigner — AWS SDK for Ruby V3

signer = Aws::S3::Presigner.new
url = signer.presigned_url(:get_object,
                           bucket: バケット名,
                           key: キー,
                           expires_in: 30)

すると、例えば以下のような URL が返ってくる。

https://my-s3-domain.s3.ap-northeast-1.amazonaws.com/record.wav?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=%2F20211219%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20211219T073726Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host&X-Amz-Signature=********

この録音 URL でのみ、対象の S3 へアクセスできるようになる。

メリット

  • 時間制限を極端に短くすることで、仮に録音 URL を知られても部外者の再生を不可にさせられる
  • S3 に保存することでコストダウン
  • S3 に録音ファイルを保存することで、AWS の面白い音声処理系 API が使える

デメリット

  • 特定の URL を生成できる環境でのみ再生が可能なため、シェアは難しい
  • 実装やアクセス制限の処理が手間

セキュリティを意識してるのに、シェアできたら聞けるは問題なので、デメリットではないか。しっかりと実装すれば、もはやメリットしかない。

終わりに

今回は Twilio 側で提供されている標準の録音セキュリティ対応と、それをせずに自前で 録音セキュリティを実装する案について記した。

結局は、利用者が 「どこまで公開を許容できるか」にかかってくる。公開を許容することによるメリット。そして公開されたことによるリスク。それぞれをしっかりと理解して、利用者にとって最適な状態を選択できるようにすることが、Twilio 録音管理にとって最も大切になってくる。

セキュリティ、セキュリティ、セキュリティ!その中でインターネットだからこそのシェアの便利さも。

今年もブログを読んでもらってありがとうございます。来年はもっと書けるように、引き続きプログラマーを楽しんでいこう~