-
Notifications
You must be signed in to change notification settings - Fork 203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CORSの範囲を制限し、無関係なリクエストを弾く #392
Comments
ありがとうございます!! VOICEVOXを起動している場合、ブラウザからリクエストを飛ばしたり情報を取得できたりするのはセキュリティ的に良くないとずっと思っており、これを防ぐ方法を探りたいなと考えています。 そもそもちゃんと知らないのですが、 あとVOICEVOXエディタからのリクエストはちゃんと受け付けられるようにする方法があればぜひ知りたいです。。 ご存じの方がいらっしゃったらぜひコメントいただけると嬉しいです。 |
誤解がありました。VOICEVOXエディタもブラウザ(でElectronの真似事をしたとき)同様 未検証ですが、 ユーザーが必要に応じて |
質問への回答
アクセスしても情報が(JavaScript側で)取得ができなくなるパターンと、リクエストを飛ばすこともできなくなるパターンがあります。どちらを使うかはブラウザ側の判断です。(https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#preflighted_requests) リクエストを飛ばすこともできなくなるパターンブラウザは、本命のリクエスト(DELETE, POSTメソッドなど)の前にVOICEVOXエンジンにプリフライトリクエスト(OPTIONSメソッド)を送ります。そのレスポンスの アクセスしても情報が取得ができなくなるパターンブラウザは、JavaScriptの指示通りにVOICEVOXエンジンにリクエスト(GETやPOSTメソッド)を送ります。VOICEVOXエンジンはレスポンスを返します。ブラウザはレスポンスヘッダの 具体的にVOICEVOXを起動してからの様子を追ってみましょう
VOICEVOXの起動エディタがエンジンにバージョン情報を問い合わせます エディタがエンジンにspeakersを問い合わせます エディタがエンジンにspeaker_infoを問い合わせます ここまでが起動時の通信です。speaker_infoは(必要なだけ)複数回問い合わせます。これまでの間、プリフライトリクエストはありません。次に、四国めたん(あまあま)に「あ」と言わせます。 音声の合成エディタがエンジンのaudio_queryにリクエストを送ります エディタがエンジンのaccent_phrasesにリクエストを送ります エディタがエンジンのsynthesisにプリフライトリクエストを送ります エディタがエンジンのsynthesisにリクエストを送ります 結果この一連のリクエストでプリフライトリクエストが必要だったのは、synthesisへのリクエストだけです。他はプリフライトリクエストを送っていません。 このように、情報が取得ができなくなるパターンと、リクエストを飛ばすこともできなくなるパターンをリクエストに応じて使い分けています。 例えばsynthesisにプリフライトリクエストを送らず、JavaScriptから情報が取得ができなくなるパターンが選択されたとしましょう。これではリクエスト自体は通常通り処理されるので、CPUやGPUリソースを消費することになります。したがって、リクエストを飛ばすこともできなくなるパターンのほうが安心です。 |
まとめとご教示ありがとうございます!! CORSの仕組みを使えば、 POSTリクエストを受け付けないようにする場合は、プリフライトリクエストの仕組みを使うことで防止もできそうだということも理解できました! 問題を整理すると、3点考えることがありそうです。
いろいろ考えたのですが、「Originがhttp/httpsなら無視する処理をサーバー側に持たせる」のが良いのかもと思いました。 ただ、サードパーティーが利用するHTTPリクエストライブラリが、Originをhttpとして送信している可能性もあるかもしれません。 あと、http/https以外に、悪意のあるサイトからlocalhostに対してリクエストを飛ばせる仕組みがあるかもと懸念しています。例えば |
これはイタチごっこの予感がしますね!! 一つ突破する方法を思いつきました。FireFoxでは対策済みでしたが、Google ChromeではOriginを偽装できるかもしれません。 これはGoogle Chromeの脆弱性かもしれないので、この場で手法を公開することは差し控えさせていただきます。(TwitterのDMで送ります。) この場合、Originはnullを返します。 http, httpsに加え、nullもブラックリストに入れると対策できます。弊害として、ブラウザで開いたローカルのHTMLファイルもエンジンにリクエストを出せなくなります。(fileスキームのOriginはnullを返します。) |
Originが http://localhost や http://127.0.0.1 とそのポート番号違い(http://127.0.0.1:50021 など)の場合は許可して問題ないと思います。( トリッキーなケースとして、自身のローカルIP(例えば http://192.168.10.102 )も許可して問題ないでしょう。(同様に、許可する必要があるかは分かりませんが。)ただし、その他のローカルIPは許可すべきではありません。(正直、全部不許可でいいと思います。) また、Originを渡さないリクエストも許可して良いと思います。(Originを渡さないのと 敗者復活戦ブラウザの拡張機能としてWEBページの読み上げをする場合、どのようなOriginを渡すか分かりません。(未定義という意味ではなく、私が知らないということです。)なんとなくhttps:// かchrome-extension:// など独自のスキームを返す気がします。無論、そんなスキームは発見次第即ブラックリスト行きです。しかし、利用者の明示的な許可があれば通しても良いでしょう。例えばVOICEVOXエンジンで固有の(予測困難な)トークンを発行し、そのトークンを利用者がコピペできるようにします。そして、ブラックリスト入りしたOriginたちはトークンを渡さないとリクエストを拒否されます。(あるいは無視されます。)したがって、ブラックリスト入りしたOriginを渡すアプリは利用者にVOICEVOXトークンを求める必要があり、利用者はトークンをコピペするかどうかで明示的な許可を与えることができます。 |
詳細にありがとうございます! 方針としては、まずレスポンスを返さないようにするのを優先的に直すことを考えると良いのかなと思いました。(辞書などに含まれるかもしれない個人情報を守るのが一番大事だと考えています。) ちなみに、VOICEVOXエディタがappプロトコルなのはここのコードによるものだと思います。 この影響は @ts-klassen さんの仰る通り、ブラウザを介するサードパーティーアプリが動かなくなるかもしれません。 CORSを設定できたら、リクエストを弾く(処理をキャンセルする)のを進めるのが良いのかなと思いました。 予測できる影響は、先ほど同様ブラウザを介するサードパーティーアプリだけですが、予想外の影響があるかもしれないので、こちらの方法はCORS設定ができたあと慎重に行いたいです。 |
@ts-klassen さん、もしよかったらCORS設定を導入するプルリクエスト作成に挑戦してみませんか・・・?👀 もしわからないこと等がありましたらなんでも聞いて頂けますと幸いです! |
挑戦してみます。 |
おー!!ぜひ…!! |
いったんこちらのタスクをまとめてみます。
|
すみません、放置してました。 |
@Hiroshiba さん
localhostや127.0.0.1ですが、もし本番用途で不要あれば、開発環境限定の環境変数などで許可対応するのがよいかと思いましたがいかがでしょうか。 PRの件ですが、エンジン側についてはともかくエディタ側(特にVue, CSS)の知見が少ないため、全ての対応は難しいと考えています。協力できる範囲であればご相談ください! |
@ts-klassen さん |
@masinc さん
VOICEVOXエディタにとってはlocalhostなどは不要なのですが、エンジンだけ使いたいサードパーティアプリではそうでもないのかなーと思っています。 なんとなくですが、指定なしだった場合は「VOICEVOXエディタからのリクエスト・
お言葉ありがたいです! |
@Hiroshiba さん
はい、私もほぼ同様の実装を想定していました。
なるほど。既存のサードパーティアプリがどのようなものが存在するのかわかっていないのですが、Webブラウザエンジン経由でHTTP通信するアプリ以外は基本的には問題無いと思われますので、オプションでの指定のみで十分対応できるのかと考えていました。 |
返信ありがとうございます、助かります!
たしかにブラウザ経由以外は全く問題なさそうに思いました。
たしかにそうですね!localhostも無条件許可で良いかも・・・? |
@masinc さん |
こちらのissueですが、 |
もしよければ |
作業に入る前に、現状のおさらいです。 CORSを設定した時点で、情報をJavaScriptに抜き取られないようにするという目標は達成しました。 Originでリクエストを弾く処理をつけようという方針になった理由に、プリフライトリクエストを飛ばさないタイプのリクエストが脅威たりうると考えたからです。 まず、Originでリクエストを弾く処理でGETリクエストは防げません。(今気づいた。どうしよう…) 一方、POSTなどは対策できそうです。 試しにVOICEVOXの代わりにnetcatを50021ポートで待機させると、 Bashコマンド「netcat -l 50021」の結果
のように 本質的にはクロスサイトリクエストフォージェリ(CSRF)対策みたいなものだと思いますが、トークンを発行するような破壊的変更は避けたいです。 もっと良い方法があれば是非! |
まとめありがとうございます! ちょっと認識が食い違っているのかもなのですが、この場合でもGETリクエストは防げない(弾けない)感じでしょうか 👀 |
API実装気を付けないとDoSできちゃいますね。。
私もこの方針には同意見ですが、トークンを利用しないとミドルウェアなどでの一元的なCSRF対策は厳しそうと思いました。
ブラウザの GET リクエストは Originヘッダを送ってこない様々なパターンがあり、それを正確に対応するのは厳しそうです。この記事がわかりやすいかもです。 |
@masinc さんありがとうございます!! キャッシュと連続リクエスト対策、ありだと感じました。 |
CORS設定を取り込んだリリースを作ってみました。7zを展開したらexeが出てきます。ちゃんと弾かれるはず・・・? |
取り掛かります。 |
おお!!よろしくお願いします・・・! |
PR&レビューありがとうございます!! 現在頂いたPRをマージしたmasterブランチでプレビュー版をビルド中です。 |
今回の仕様変更の影響をユーザーの方に案内をしたいのですが、ちょっと複雑な段取りを取ろうと思います。
というのも、これらの要件を満たしたいためです。 ・愉快犯を防ぎたい(ので詳細を伏せる) また、普段機能追加PRをマージしたときはツイッターでPRリンク付きツイートをさせていただいている(例)のですが、もしツイートすると愉快犯が現れてしまうかもと考えています。 |
サードパーティアプリ開発者の方向けに案内する予定のissueを作成しました。もし語弊などあればご指摘頂けると嬉しいです・・・! |
例えば「VoiceSissy for VOICEVOX」というChrome拡張機能では、 これについて、拡張機能の開発者が対応できることはなく、利用者自身が上記のOriginを許可する必要があります。 VOICEVOXエディタに許可するOriginを入力できる機能をつける必要があるのではないでしょうか。 |
情報ありがとうございます!! |
エンジン側に設定機能を持たせる方法がありました。 例えばStreamlitでwebページを作成して、 エンジンだけで音声合成チェックする需要もあるはずですし、エンジン側にGUIをもたせるのはいろいろ便利そうです。 |
ブラウザ拡張についてですが、Google Chrome 101+(>=の意。Chrome 101は2022-04リリース。2022-12-04時点の最新の安定版はChrome 108)およびManifest V3で、
またCORSについては、
具体的な実装例を置いておきます。
// license: CC0
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: [1],
addRules: [
{
id: 1,
priority: 1,
action: {
type: 'modifyHeaders',
requestHeaders: [
{ 'header': 'Origin', 'operation': 'remove' },
],
},
condition: {
urlFilter: '127.0.0.1:50021/*',
initiatorDomains: [chrome.runtime.id], // chrome-extension://{chrome.runtime.id}
},
},
],
}) |
なるほど!!chrome拡張側のコード変更でCORS回避できるんですね!!盲点でした。 拡張機能開発者の目線だと、ユーザーにCORSの設定をしてもらわなくて済むのでこちらの方が好まれそうですね。 いろんな需要があると思う(普通にwebページからリクエスト飛ばしたいとか)ので、CORSを設定する方法も提供できると嬉しいのかなと思いました! |
が解決されたので案内を進めていきたいと思います! discordで聞いた感じだと、chrome系アプリの他には影響ない感じでした。 他に影響ありそうなシステムがないかを僕の個人アカウントからツイートして公募中です。 ちょっと時間たってからVOICEVOX公式から案内したいと思います! |
こちら確か案内も済ませて、特に問題なく完了した記憶があります。 |
内容
Access-Control-Allow-Origin: *
は変えたほうが良いかもしれない(要議論)ヒホさんとTwitterのDMで話した内容を詳しく書きます。
現状
VOICEVOXエンジンとエディタのオリジンが違うため、JavaScriptでのリクエストはCORS上の問題が発生する。現在、エンジン側のヘッダで
Access-Control-Allow-Origin: *
と返すことで異なるオリジンからのリクエストを許可している。変更すべき点
現状ではapp以外からのJavaScriptリクエストも許可してしまうため、
Access-Control-Allow-Origin: app://.
に書き換えるべきである。(要検証)app以外からも許可している現状の問題点
VOICEVOXを起動した状態で悪意のあるサイトを開くと、知らぬ間にVOICEVOXエンジンへリクエストが飛ぶ可能性がある。
再現方法
VOICEVOX0.11.4をLinuxで起動した。(
$ /path/to/VOICEVOX0.11.4/run
)google chromeで https://voicevox.su-shiki.com/su-shikiapis/localtests/ にアクセスし、InspectのNetworkを開きリロードした。
送信ボタンを押した。
送信に成功し、
/path/to/VOICEVOX0.11.4/run
の標準出力に127.0.0.1:37768 - "POST /synthesis?speaker=1&enable_interrogative_upspeak=true HTTP/1.1" 200 OK
と出力された。原理
そもそもCORSはブラウザの自主規制である。chromium系であれば起動時のオプションに
--disable-web-security
とつければ無効化できる他、JavaScriptを介さないリクエストや、ブラウザを使わないリクエスト(curlなど)に対し何ら効果を発揮しない。しかし、Electronがchromiumをベースにしているため、web-securityを無効化しない限り別オリジンへJavaScriptリクエストを出せないのである。実演
すべてのオリジンを許可するv1apiと、同一オリジンのみ許可するv2apiを用意した。
v1api; https://api.su-shiki.com/v1/localtests/
v2api; https://api.su-shiki.com/v2/localtests/
無論、ブラウザやcurlで直接アクセスすることを妨げるものではない。しかし、別オリジン(ホストが違うなど。スキームやポート番号が違っても別オリジンである。)のJavaScriptでリクエストを飛ばすとブラウザが止めてくれるはずである。
v1api; https://voicevox.su-shiki.com/su-shikiapis/localtests/v1api.html
v2api; https://voicevox.su-shiki.com/su-shikiapis/localtests/v2api.html
VOICEVOXエンジンとエディタは別オリジンである
エンジンが
http://127.0.0.1:50021
であるのに対し、エディタはapp://.
であるため、レスポンスヘッダでAccess-Control-Allow-Origin
を正しく返さなければならない。Access-Control-Allow-Originを変える
Access-Control-Allow-Origin: app://.
を返すと良いだろう。(要検証。本当に弊害がないか。)app以外からの利用
例えばブラウザの拡張機能としてVOICEVOXを利用するなど、JavaScriptでリクエストする場合、
Access-Control-Allow-Origin: *
とせざるを得ないこともある。Pros 良くなる点
利用者の意図しない形で、第三者にVOICEVOXエンジンへリクエストや任意の文字列を送信される可能性を減らせる。
Cons 悪くなる点
ユーザーの利用目的や連携先(外部ホスト)に応じて、セキュリティー設定を利用者自身が変更する必要がある。
検証時のVOICEVOXバージョン
0.11.4
検証時のOSの種類/ディストリ/バージョン
Linux inty 5.15.0-27-generic #28-Ubuntu SMP Thu Apr 14 04:55:28 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Linux kali 5.15.0-kali3-amd64 #1 SMP Debian 5.15.15-2kali1 (2022-01-31) x86_64 GNU/Linux
その他
The text was updated successfully, but these errors were encountered: