
【知識の泉】🌟 「CORSでAPI叩けない!」
例によって読者置き去りの記事ですが、下ののネタのCORSの解説です。
記事の内容自体は実用的なはずです。
🌟 「CORSでAPI叩けない!」の本当の意味
まず大事なのは、
「CORSがブロックしてるんじゃなくて、SOP(Same-Origin Policy)がブロックしてる!」
「CORSを正しく設定すれば、SOPのブロックを解除できる!」
🌟 SOP(Same-Origin Policy)がAPIをブロックする
SOP(同一オリジンポリシー)は、ブラウザが持っているセキュリティルール。
「異なるオリジンのリソースを勝手に取得できないようにする」仕組みになっている。
例えば、
フロントエンド(React, Vue, etc.)のオリジン → http://localhost:3000
バックエンド(APIサーバー)のオリジン → http://localhost:8000
この状態で、フロントエンドからAPIを叩こうとすると👇
fetch("http://localhost:8000/api/data") // ← オリジンが違う!
💥 SOPによってブロックされる!
🌟 「CORSエラー」の正体
実際にAPIを叩くと、ブラウザのコンソールに次のようなエラーが出る👇
Access to fetch at 'http://localhost:8000/api/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
このメッセージのポイントは、
"blocked by CORS policy" → 実際は SOPがブロックしている
"No 'Access-Control-Allow-Origin' header" → CORSを設定すれば解除できる!
🌟 CORS(Cross-Origin Resource Sharing)とは?
CORS は「このAPIは異なるオリジンからのリクエストを許可してOK!」とAPI側が伝える仕組み。
API側で Access-Control-Allow-Origin を返せば、SOPのブロックを解除できる!
🌟 CORSを設定してSOPのブロックを解除する
API(バックエンド)側でCORSを設定すれば、異なるオリジンからのアクセスが許可される。
✅ 例1️⃣ axum で CORS を許可する(どこでもOKな設定)
use axum::{Router, routing::get};
use tower_http::cors::CorsLayer;
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(handler))
.layer(CorsLayer::permissive()); // どのオリジンからでもOKにする!
axum::Server::bind(&"0.0.0.0:8000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler() -> &'static str {
"Hello, CORS!"
}
📌 CorsLayer::permissive() を使うと、どのオリジンからのリクエストも許可される! 🚀✨
📌 ローカル開発時には便利だが、本番では制限をかけるべき!
✅ 例2️⃣ フロントエンド(React, Vue)だけを許可する
本番環境では「どこでもOK」ではなく、「特定のオリジンだけOK」にするのがベスト。
use axum::{Router, routing::get};
use tower_http::cors::{CorsLayer, Any};
use http::Method;
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
let cors = CorsLayer::new()
.allow_origin("https://frontend.example.com".parse().unwrap()) // 特定のオリジンを許可
.allow_credentials(true) // 認証情報を送れるようにする!
.allow_methods([Method::GET, Method::POST]);
let app = Router::new()
.route("/", get(handler))
.layer(cors);
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
println!("Listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler() -> &'static str {
"CORS is configured!"
}
📌 「特定のオリジンだけ許可 + allow_credentials(true)」が最も安全! 🚀✨
次に、「*(ワイルドカード)を使うと超危険!」 という話に入るよ! 🔥🔥🔥
🌟 「CORSが面倒だから * を設定すると超危険!」
💥 結論:*(ワイルドカード)を CORS の Access-Control-Allow-Origin に設定すると、セキュリティ的にヤバすぎる! 💥
✅ そもそも Access-Control-Allow-Origin: * って何?
👉 「どのオリジン(ドメイン)からのリクエストも許可する!」 という設定。
👉 つまり、インターネット上のどのサイトからでも API にアクセスできる!
📌 こんな設定は危険!
use tower_http::cors::CorsLayer;
let cors = CorsLayer::new()
.allow_origin(tower_http::cors::Any) // ❌ どこからでもOK!(超危険!)
.allow_methods([Method::GET, Method::POST]);
🔥 この設定だと…
悪意のあるサイトから勝手にAPIを叩かれる! 🚨
CSRF(クロスサイトリクエストフォージェリ)が発生する! 💀
APIキーや認証情報が盗まれるリスクがある! 🕵️♂️
🔥 *(ワイルドカード)の危険性を具体的に解説!
1️⃣ APIが意図しないサイトから使われる!
例えば、API のエンドポイントが https://api.example.com/data にあるとする。
普通なら、許可されたフロントエンド (https://frontend.example.com) だけがアクセスできるべき。
でも、* を使うと どのサイトからでも勝手にアクセスできる! 💀
<script>
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log("Hacked Data:", data));
</script>
👉 攻撃者のサイトが勝手にAPIを叩いて、データを盗める! 🚨
2️⃣ 認証情報が漏れる可能性がある(credentials: true と * の組み合わせ)
🚨 「CORS の * を設定すると、認証情報(クッキーやトークン)が送れなくなる」→ これを無理に回避しようとすると超危険!
❌ 超ヤバい設定(やっちゃダメ!)
let cors = CorsLayer::new()
.allow_origin(tower_http::cors::Any) // ❌ どこでもOK
.allow_credentials(true) // ❌ `*` と `credentials: true` は併用禁止!
.allow_methods([Method::GET, Method::POST]);
📌 ブラウザの仕様で「* と credentials: true を一緒に使うとエラーになる」
だから allow_credentials(true) を設定すると、allow_origin("*") が使えなくなる!
📌 でも、攻撃者が「ワイルドカードをやめて、全部のオリジンを許可する」設定に変えさせることがある!
let cors = CorsLayer::new()
.allow_origin(["https://malicious-site.com", "https://frontend.example.com"]) // ❌ 攻撃者のサイトを含めちゃった!
.allow_credentials(true) // ❌ Cookie が送られる!
.allow_methods([Method::GET, Method::POST]);
💀 攻撃者のサイト (https://malicious-site.com) も許可されていると…
ログインしているユーザーが https://malicious-site.com にアクセスすると、自動でクッキーが送信される!
CSRF(クロスサイトリクエストフォージェリ)攻撃のリスクが爆増! 🚨
👉 認証情報(JWT, セッションID, APIキー)が盗まれる可能性がある!
🌟 じゃあ、CORS はどう設定すべき?
✅ 1️⃣ 本番では * を絶対に使わない!
✅ 2️⃣ allow_origin() で特定のオリジン(フロントエンドのURL)を指定!
✅ 3️⃣ 認証情報を使うなら、allow_credentials(true) も忘れずに!
✅ 正しい CORS の設定例
use axum::{Router, routing::get};
use tower_http::cors::{CorsLayer, Any};
use http::Method;
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
let cors = CorsLayer::new()
.allow_origin("https://frontend.example.com".parse().unwrap()) // ✅ フロントエンドのオリジンだけ許可!
.allow_credentials(true) // ✅ 認証情報を送れるようにする!
.allow_methods([Method::GET, Method::POST]);
let app = Router::new()
.route("/", get(handler))
.layer(cors);
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
println!("Listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler() -> &'static str {
"CORS is configured!"
}
📌 「特定のオリジンだけ許可 + allow_credentials(true)」が最も安全! 🚀✨
🎯 まとめ
🚨 「CORSが面倒だから *(ワイルドカード)を設定するのは超危険!」
🚨 特に credentials: true と * の組み合わせは、APIキーや認証情報漏洩のリスクが爆増!
✅ 本番環境では allow_origin("*") は絶対にNG!
✅ allow_origin("https://frontend.example.com") で特定のオリジンだけ許可!
✅ 認証が必要なら allow_credentials(true) を追加!
📌 CORS の設定ミスは「開発者が知らないうちに API が乗っ取られる」リスクがあるから、超重要! 🚨🔥
📌 「とりあえず * で許可すればいいや」はダメ!ちゃんと allow_origin() を設定しよう!
🔥 これで「CORSでAPI叩けない!」問題の完全版、完成! 🚀✨
また 「この設定って本当に安全?」 って思ったら、いつでも聞いてねー!🔥🔥🔥