Upgrade to Pro — share decks privately, control downloads, hide ads and more …

疎通2024

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for sadnessOjisan sadnessOjisan
September 07, 2024

 疎通2024

Avatar for sadnessOjisan

sadnessOjisan

September 07, 2024
Tweet

More Decks by sadnessOjisan

Other Decks in Technology

Transcript

  1. コンポーネントカタログの限界 • story ファイルを用意するのが大変 • story と相性の悪いライブラリや実装もある • story のメンテナンスが困難

    ◦ spec の追従 ◦ ライブラリの更新 ◦ 増えるコンポーネントや追加仕様に対する追従 • 完璧にstoryを用意してもフロントエンドの正しさしか表現できない ※ story は storybook に限らず open な spec. https://github.com/ComponentDriven/csf
  2. API Spec • Client, Mock Server, TypeDef, Validator を生成でき、ドキュメントとしても 利用できる

    • レスポンスの型が分かるので、実APIを叩かずに開発を進められる
  3. Swagger Code Gen • OASがあれば Swagger エコシステムからモック サーバーを立てられる • jar

    や docker image でジェネレータが配布されて いる • docker run --rm -v ${PWD}:/local swaggerapi/swagger-codegen-cli-v3 generate -i /local/spec.yaml -l nodejs-server -o /local • モックサーバーの出来は言語によってまちまち
  4. CORS をケアしないといけない • SwaggerUI からのリクエストに対す るレスポンスを返すサーバーとして 動作する • 開発のためのモックサーバーとして 動作させるためには、CORSをケアす

    る必要がある • モックサーバーを生成後、人力で サーバーを改変しないといけない • 具体的には utils/writer.js に CORS のためのヘッダーを差し込む
  5. Cookieがセットされない • swagger-ui から認証をしても set-cookie されないことがある • しかしモックサーバーの実装によっては、Cookie を使うことを明記している と、Cookie

    がないリクエストは不正リクエストとして弾かれる • そこでブラウザのインスペクタから無理やり cookie をつける
  6. ハードルは高い • 動作確認が悩ましい ◦ 確認のたびにコンテナをビルドするのはサイクルが悪い ◦ 確認対象だけそのまま起動させたいが、そのためには docker compose up

    で立ち上げたものの うち、不要なものを手動で落とさないといけない • 結局は認証やらで外部SaaSに頼ると、そのシークレットを持ち回る必要があ る。自チーム以外のシークレットの管理はしたくない • 開発に携わるチームメンバー全員が熟練者である必要がある。連携を密にとれ る必要もある。
  7. よくある誤解: CORS がセキュリティを守っている • 🔺「CORSエラー」 • ❌「CORSに弾かれた」 • ❌「CORSが守っている」 •

    ⭕セキュリティを守っているのは Same Origin Policy とブラウザ。CORSは どちらかというとそこに安全に穴を開けるための仕組み
  8. Same Origin Policy は何から我々を守っているのか • 同一オリジンポリシーは重要なセキュリティの仕組みであり、あるオリジンに よって読み込まれた文書やスクリプトが、他のオリジンにあるリソースにアク セスできる方法を制限するものです。https://developer.mozilla.org/ja/docs/Web/Security/Same-origin_policy • ブラウザが取り入れているセキュリティポリシー

    • 例: https://atack.ojisan.dev から取得した JS からは、 https://atack.ojisan.dev 以外のリソースにリクエストして、情報を読み取る ことができない。 • 注: ブラウザが情報を読み取ることを防いでいるだけで、リクエスト自体は送 信できていることに注意(後述する preflight に議論が繋がる)
  9. preflight • CORS のプリフライトリクエストは CORS のリクエストの一つであり、サー バーが CORS プロトコルを理解していて 準備がされていることを、特定のメソッ

    ドとヘッダーを使用してチェックしま す。 • これは OPTIONS リクエストであり、 Access-Control-Request-Method,Acc ess-Control-Request-Headers, Origin の 3 つの HTTP リクエストヘッダー使 用します。 https://developer.mozilla.org/ja/docs/Glossary/Preflight_request preflight request OPTION 204 + CORS(origin, method, header) Post 不正なリクエストはこ こで止められる
  10. サーバーの対応だけでいいのか • CORS自体はサーバーが返すヘッダーで制御するが、クロスオリジンのリクエ ストを成功させるためにはクライアント側にも仕事がある • ここでいう credentials は、Cookie, 認証ヘッダー, TLSクライアント証明書

    • つまり、Cookieを付けて fetch する場合、`credentials: true` を付けてリクエ ストしないといけない • Access-Control-Allow-Credentials: true をサーバーが返す必要がある。 Request.credentials が include である場合、レスポンスを JS に公開してい いことをブラウザに伝えるフラグ
  11. credential は Cookie の受信にも関係する • "omit" ◦ Excludes credentials from

    this request, and causes any credentials sent back in the response to be ignored. • "same-origin" ◦ Include credentials with requests made to same-origin URLs, and use any credentials sent back in responses from same-origin URLs. • "include" ◦ Always includes credentials with this request, and always use any credentials sent back in the response. https://fetch.spec.whatwg.org/#concept-request-credentials-mode
  12. fetch の mode • fetch には mode option があり、cors を指定できるが、どのように設定すべ

    きか • 設定は意識しなくて良い。fetch でリクエストを作ると自動で cors となる
  13. CSRFトークンのことを忘れていると疎通で痛い目を見る • サーバーのFWによっては CSRF トークンを使うことがデフォルト設定のもの がある • 例: https://docs.djangoproject.com/ja/5.1/howto/csrf/ •

    その挙動を参考にして作られた API Spec から生成した Swagger Client(zodious) を使っていたら、ある日急に例外を吐くようになって焦った 思い出
  14. なぜ Cookie を使いたいのか • HTTP は stateless なのでログインしたユーザーであることをサーバーに伝え る手段を持たないといけない •

    Cookieはサーバーが勝手に読み取ってくれる上に、ブラウザが勝手に永続化 してくれる • 仕様も安定していたり、インターネットに情報も多い なんだけどなんかよくトラブルに出会うんだよな
  15. fetch で Cookie を付けてみよう • 先の Cookie を付けた画像例は、set-cookie するエンドポイントに直接ブラウ ザでアクセスした

    • 代わりに set-cookie してくれるエンドポイントにlocalhost から fetch して みよう • CORS が必要でこける
  16. Access-Control-Allow-Credentials も必要 • {credentials: 'include'} を使うならセットで Access-Control-Allow-Credentials: true が必要 •

    その結果、クッキーがブラウザにセットされる • ただし SameSite 属性の部分で警告が出ていて、まだこのままだと送信ができ ない
  17. Domain 属性に自由な値は入れられない • localhost:3000 で待ち受けているサーバーに localhost:3000 からアクセス し、set-cookie で example.com

    をセットしようとするとエラー。 • リクエストのHostに対してしかクッキーをつけれない。 • つまり example.com にアクセスして example.com が set-cookie しないとつ けれない。
  18. Noneにするなら Secure 属性が必要 • Cookie送信をやり切るために、一旦 None を指定してみる • SameSite=None は

    Secure と一緒に使う必要がある(※1)ので、ブラウザは クッキーを送ってくれない • (SameSite 関係なく Secure 属性は付けた方が良いと思う) ※1: https://developers.google.com/search/blog/2020/01/get-ready-for-new-samesitenone-secure?hl=ja
  19. SameSite=None は使いたくない • None は CSRF の脅威にさらされる • ブラウザのデフォルトは Lax

    であり、リンクの遷移を除いてクロスサイトに クッキーを送らない • クロスサイトを諦める必要がある?
  20. Domain vs Origin vs Site • Domain: サブドメイン + メインドメイ

    ン + トップレベルドメイン • Origin: プロトコル + Domain + ポート • Site: Domain のeTLD+1 • 例: https://developer.mozilla.org/ja/docs/ と https://support.mozilla.org/ja/ は、Siteが一致していて、Origin は異な る。 便利画像 https://blog.jxck.io/entries/2023-12-21/same-site.html
  21. CORS や secure 属性の制約を考える • hosts を使ったとしても、実URLは HTTPS なので localhost

    の名前解 決をしただけでは疎通ができない • ローカルホストの HTTPS 化が必要
  22. ローカルで HTTPS サーバーを起動するためには • ルート証明書となるオレオレ証明書を発行 • ルート証明書をマシンに登録する • ルート証明書を使ってサーバー証明書を作る •

    HTTPSをサポートしているWebサーバーにサーバー証明書を読み込む • ルート証明書を持っているマシンからそのサーバーに対してHTTPS通信ができ る
  23. mkcert の使い方 • mkcert ◦ 自己認証局用の証明書・秘密鍵を作る mkcert -install ◦ ルート証明書としてマシンに登録

    ◦ サーバー証明書を作る mkcert example.com ◦ サーバーに生成された証明書と秘密鍵を読み込ませる (サーバー側の機能として大体持ってる、 https://nginx.org/en/docs/http/configuring_https_s ervers.html • コマンドには sudo が必要 • マシンに mkcert の証明書が作られてしまう • 意味を分からずに叩いて良いコマンドではない!
  24. Next.js の開発サーバーが HTTPS で立つらしい • `next dev --experimental-https` • 開発サーバーを立てようとするとマ

    シンのパスワードを求められる • mkcert がインストールされる • ルート証明書が登録される • サーバーを落としてもルート証明書 は残り続ける • (あまり触りたくないな...) https://vercel.com/guides/access-nextjs-localhost-https-certificate-self-signed
  25. LaxのためにローカルのURL書き換え、絶対ちがう!!! • 元々 SameSite=Lax で提供されるログインクッキーを使って、ローカルホス トで開発をしたかったのが始まり • そのために sudo mkcert

    しますか? • そのために sudo vim /etc/hosts しますか? • sudo 使いますか?マシンの設定を直接書き換えますか? • 開発終了後にちゃんと戻しますか? • もしうっかりなにかやらかしたらリカバリーできますか? 怖
  26. Vite の web proxy が便利 • /api へのアクセスを全部、https://api.ojisan.dev に変換してくれる。 •

    つまり、叩くAPIのURLを全部、localhost:3000/api にしておけば、本番URL にプロキシしてくれる • VITE_API_ORIGIN=http://localhost:3000/api などとしてAPIの通信箇所を 自分自身のURLにしておけば、SameSiteとなる // vite.config.js export default { server: { proxy: { "/api": { target: "https://api.ojisan.dev", changeOrigin: true, secure: false, rewrite: (path) => path.replace(/^\/api/, ""), }, }, }, };
  27. HSTS とその強制 • HTTP の Strict-Transport-Security レスポンスヘッダー (しばしば HSTS と

    略されます) は、ウェブサイトがブラウザーに HTTP の代わりに HTTPS を用 いて通信を行うよう指示するためのものです。 https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Strict-Transport-Security • .app ドメインと .dev ドメインは HSTS が強制される!!!! • 何かの IPアドレスに手持ちの appドメインやdevドメインを貼って疎通しよう とすると、疎通相手が HTTPS 対応しないと疎通できない • ブラウザからは疎通できないのに、cURL だと疎通できる奇妙な状況になるの も芸術点が高い • 今日の実装例紹介で急に vercel の app ドメインから ojisan.io に変わったの はこれが理由です。(ちなみに cfw 逃げようとしましたが cf も .dev です)
  28. cache-control: no-store でもキャッシュするCDN • 名指しはしませんが、CDN によっては no-store だけならキャッシュするものが ある •

    仕様違反かどうかは Cahce解体新書を読ん で確かめよう • CDNを使うのは疎通段階、下手したら本番 環境まで使わないかもしれないので、検知 が遅れがち https://zenn.dev/jxck/books/cache-anatomia
  29. 通らない STUN • WebRTCを実務で使うには STUN ではなく TURN を使うのが定石だとは思う が、TURN サーバー契約する決済が降りず、偶然

    STUN だけで事足りていたの で STUN のまま実装していた • 客先に納品後しばらくしてとある携帯事業者だけ繋がらないというバグ報告を 受けた • QAの段階で wifi に繋いでOSごとのQAはしていたが、4G回線の比較はしてい なかった • TURN 使おう、契約回線もQA事項に入れよう
  30. modheader の消し忘れ • 動作確認のために authorization を書き換える • これで GitHub, Twitter,

    ChatGPT を開くと、ログインはできているのにコン テンツのロードができない謎挙動を楽しめる • 使ったら戻そう || フィルター使おう