いろいろググって調べた結果、「Access-Control-Allow-Origin ヘッダ」を使い、
ドメイン指定してリクエストを受け付ければcsrf対策はなんとかなりそうかなと思っています。
PHP側にそのヘッダーを、ということでしたら、
そちらのヘッダは非同期通信にしか効果を発揮しないため、
フォームによるPOST通信に対しては無意味です。
こういった場合は一般的にどうやってcsrf対策するものなんでしょうか?
そもそもフォームと送信先のドメインが違うケース自体がイレギュラーですので、やり方は限られると思います。
A = フォーム送信先
B = フォーム設置先
案1
A、Bのサーバサイドで同じ鍵により、生成と検証ができるトークンが前提。
- Bでトークンを発行し、フォーム生成時に送信値としてFORMタグに含める。
- そのトークンをAで認証できるようにする。
案2
BがPHPなどで作成できない場合は、
Aにトークンを発行するためのAPIを作成、ヘッダにAccess-Control-Allow-OriginでBのドメイン指定、
Bのフロントから非同期でそのAPIを叩き、フォームの送信値にセットするようにする。
トークン生成と認証(簡易例)
入力値のエラーハンドリングなど不完全ですが、参考にはなると思います。
セキュリティ強度などは要調整。
PHP
1<?php
2
3define("KEY", "test123"); //共通利用の鍵
4define("EXPIRE", 60); //トークンの有効期限(秒)
5
6//トークン取得
7$token = get_token();
8echo $token;
9echo '<hr>';
10
11//トークン認証
12$auth = auth_token($token);
13echo $auth ? 'OK' : 'NG';
14
15//トークン発行
16function get_token()
17{
18 $time = time();
19 $id = uniqid();
20 $hash = md5($id . KEY . $time);
21 $token = $hash . '_' . $id . '_' . $time;
22
23 return $token;
24}
25
26//トークン認証
27function auth_token($token)
28{
29 list($hash, $id, $time) = explode('_', $token);
30
31 //改竄検知
32 if ($hash !== md5($id . KEY . $time)) {
33 return false;
34 }
35
36 //有効期限確認
37 if ($time < (time() - EXPIRE)) {
38 return false;
39 }
40
41 return true;
42}