Origin
ヘッダー、 CORS とは
ブラウザから JavaScript で別ドメインの API 、画像、音声ファイルなどのリソースを利用するときはもろもろの脆弱性(詳しくは割愛)を防ぐため、 CORS という仕組みを使いリクエストの Origin
ヘッダーを見てアクセスを許可する場合のみレスポンスに Access-Control-Allow-Origin
ヘッダーを返してあげる必要があります。
これはブラウザのセキュリティを担保するためのものなので、ターミナルから curl
コマンドを使ったリクエストや Node.js からのアクセスなどには関係ありません。つまり React Native にも基本的には関係ありません。
オリジン間のWebSocket
WebSocket には CORS が適用されないため、 Origin
をヘッダーを見て意図しないオリジンからのアクセスを拒否するように WebSocket サーバー内で実装する必要があります。
これをしないと Cross-Site WebSocket Hijacking の危険性があります。
React Native の WebSocket の Origin
って?
前述の通り React Native に CORS は基本的には影響しませんが、 WebSocket 接続時のセキュリティを担保するための Origin
ヘッダーはどのように設定されているのでしょうか?
ドキュメントには記述が見つけられませんでしたが、 React Native のネイティブ側の WebSocket の実装をみると WebSocketの接続先の ws(s)
を http(s)
に置換した文字列を Origin
ヘッダーにセットしているようでした。
Android の実装をみると JS から Origin
ヘッダーが渡された場合その値が使われるようになっていそうですが、 iOS のほうにはそのような挙動はないようなので、 Origin
ヘッダーは渡さない方がよさそうな感じがします。
なぜこれが必要だったのか
現在のプロジェクトで Hasura という PostgreSQL から GraphQL API を生成してくれるミドルウェアを使っているのですが、 Hasura には HASURA_GRAPHQL_CORS_DOMAIN
環境変数をセットすることでCORSを許可するドメインを指定できる機能があります。
GraphQL engine server config examples | Hasura GraphQL Docs
HASURA_GRAPHQL_CORS_DOMAIN
をセットすると、同時に GraphQL Subscription の WebSocket 接続もその Origin
以外からは弾くようになっています。
Subscriptions | Hasura GraphQL Docs
この仕様は基本的にはありがたいのですが、 React Native の場合は CORS は関係ないはずなのに WebSocket のときのみ接続が弾かれてしまうという問題があり CORS の設定ができないでいました。
React Native からの WebSocket 接続があるときは、 WebSocket サーバー自体のドメインを許可する Origin
に追加すればよさそうです。
まとめと宣伝
Hasura の CORS を設定すると WebSocket が接続できなくなる問題があるため Production checklist のうち CORS の設定だけできていなかったのですが、これで一通り実践できるようになりました
最後に宣伝です。
現在 TypeScript / Next.js / React Native / GraphQL / Hasura を使った開発現場で業務委託やインターンのエンジニアを募集しています。
興味がございましたら shinnoki までご連絡下さい。