API やフォームで POST するときに特にトークンとか用意してないことも多いのですが セキュリティをちゃんと考えるならあったほうが良さそうです
どう実装するのがいいのかなと考えてみました

トークンの意味

まずトークンが必要な理由ですが 本人が普通に POST する分には特に要らないものだと思います
悪い人の攻撃を防ぐセキュリティ的なことが主な目的です
一応ワンタイムトークンにしておけば 二重 POST を防ぐとかもできますけど

普通に考えれば攻撃しようにしても 他人のログイン情報や Cookie を盗めないと何もできません
しかし ウェブの場合は自分のサイトへアクセスしてきたユーザに外部のサイトへアクセスさせることができます
そういったアクセスでも Cookie は送られます
そのユーザのブラウザからすると サイト A へのリクエストなので サイト A が作った Cookie を送るのは自然です
Cookie が送られていればログインしたユーザとしてのアクセスなので

https://service100/account/delete

みたいな URL にアクセスさせれば もしそのユーザが service100 というサイトにログインしていた場合にアカウント削除させることができてしまいます

他にもブログだと本人が書いた覚えのない記事を投稿させたり 銀行だと勝手にお金を振り込ませたりできてしまいます
ログインしないサービスでも殺害予告や迷惑行為を知らない間に他人にやらせたりできてしまいます

こういうのを防ぐ目的でトークンが使われます

Cookie の場合

ログインが必要なサービスの場合は ログインしているユーザのリクエストである必要があります
基本的には Cookie で判断するので Cookie が送られなければ未ログインとみなされ POST は無効です
Cookie に SameSite 属性をつければ 外部からのリクエストの場合に Cookie を送らないように制御できます
ログイン時に発行する Cookie にこの属性をつければトークンはなくてもこれだけで済むはずです

またログインしない場合でも とりあえず Cookie を発行しておいて POST リクエストでは Cookie が送られていることをチェックすれば外部からのリクエストでないことは保証できるはずです
fetch で headers に Cookie を指定しても送ることはできないので とりあえずの Cookie は全員同じ中身で 「1」 だけでも大丈夫そうです

そういう意味では便利な属性のはずなのですが Chrome がデフォルト値を変更したり None は https 必須にしたりしたので困ることの方が増えてむしろやっかい機能の印象の方が強かったりしますけどね

トークンの使い方

SameSite のことは一旦忘れてトークンを使う場合についてです

Cookie だと勝手に送られるので 本人が意図したリクエストでしか送られないものを用意することで 意図しないリクエストによる操作を防ぎます
トークンは Cookie 中のセッションに持たせて それと同じトークンを POST リクエストで送信します
この 2 つが一致すれば本人が意図したリクエストのはずです
外部からのリクエストではトークンが含まれないので不正とみなすことができます
ログインするものなら Cookie ではなく データベースのユーザ情報に持たせることもできます

基本的にトークンは外部に漏れることはないはずなので使い回しでも問題ないはずです

送信の仕方は フォームの場合は <input type="hidden"> を用意してサーバ側で埋め込んでしまうのがかんたんです
SPA など API でリクエストすることになるならフォーム同様 body に含めることもできますが header を使えるので header で送るのもありです

Cookie の必要性

Cookie だと自動で送られるので それとは別にトークンを手動で送ることになったのですが 手動でトークンを送るならそれ自体を Cookie の代わりにすれば良いように思いました
SPA のサイトだとサーバとの通信は API 呼び出しのみになるので すべてのリクエストの header にトークンをセットできます
このトークンを Cookie のように扱いセッションを管理してログイン判断します
実際に Cookie とは別のトークンで認証処理をする仕組みは存在します

この場合は POST のトークンと同じで手動でセットするものなので 外部からのリクエストでは送信されずログインしてるとはみなされません
Cookie の代わりにこの仕組みを使えば POST のトークンというものを意識しなくて済みますし 良い方法なのかもしれないです


手動送信するトークンでセッションを管理する場合 その情報をブラウザに保存する必要があります
そうなると localStorage などを使うことになりますが これが良くないと言ってる人もみかけます

JavaScript から操作できるのでリスクがあるとは言えますが 前提として攻撃用のスクリプトが自分のサイトで動く必要があります
XSS 対策してないとか信頼できないライブラリを埋め込むのが原因ですし そうなってる時点ですでに手遅れだと思います
そんな状況でトークンだけ守ったところでたいした意味はないと思います

トークンを盗めなくてもサービス利用者の権限で任意のリクエストをサーバへ送れます
Cookie を使って SameSite や httpOnly の制限をかけていたとしても そのサイト内からの正常なリクエスト扱いなので防げません
またそのレスポンスを悪い人たちが管理してる外部サーバへ送信もできます

JavaScript を実行できる以上 画面を書き換えて偽物の画面を出してユーザに入力を促すこともできます
「セッションが切れたのでパスワードを再入力してください」という画面を出せばユーザが認証情報を入れてくれるのでそれを外部サイトに送ることもできます

なので localStorage に保存することは問題あるとは思えません
zip とパスワードを別メールで送るくらいのほとんど効果が見込めないセキュリティ対策だと思います
それ以前の攻撃用スクリプトが自分のサイトで動くようなことがないように気をつけるべきです
そもそも いろいろなサイトで使われていて フレームワークの機能としてもサポートされているくらいですしね

まとめ

[SameSite]
外部からのリクエストで Cookie を送信しなくできる
ログインが必須なページならこれで不正な POST を防げる
ログインが不要なページでも Cookie を作っておけば不正な POST を防げる
Cookie の属性をつけるだけなのでお手軽

[トークン]
Cookie とは別に手動でトークンを送る
外部からのリクエストでは正しいトークンを送れないので不正な POST を防げる

[トークンを Cookie 代わりにも使う]
ログインが必要なときに ログインの Cookie とトークンを送るのはムダが多い
トップフレームやリソースの読み込みに Cookie が不要で API リクエストしかないならトークンを Cookie 代わりに使える
外部からのリクエストでは正しいトークンを送れないので 不正な POST を防げる
ログインのためのものになるので POST 用のトークンは不要になる