独立サイトのAPIセキュリティ:認証、レート制限、CORS、入力検証、脆弱性対策

独立サイトの外部APIの安全は、WAF一枚で守るものではなく、五つの層を重ねて初めて成立します。認証で身元を固定し、レート制限で連打を抑え、CORSでクロスドメインの穴を狭め、入力検証で不正データを遮断し、依存関係スキャンで定期的に裏口を...

独立站 API 五层安全防线:从身份到数据API security: five layers from identity to data 反直觉:只开 HTTPS 不等于安全——HTTPS 防窃听,不防重放、批量调用与注入Counter-intuitive: HTTPS alone does not stop replay, abuse or injection 防线层Layer 挡住什么Stops 关键阈值 / 动作Bar / action 1 认证1. Auth 匿名调用与冒用身份Anonymous / impersonated calls JWT 2 小时过期,密钥季度轮换JWT 2h expiry, rotate quarterly 2 限流2. Rate limit 刷接口与暴力枚举Scraping / brute force 登录 10 次/分,匿名 60 次/分Login 10/min, anon 60/min 3 CORS3. CORS 恶意站点跨域读数据Cross-origin data theft 白名单来源,禁 *. 全放开Allowlist origins, never * 4 输入验证4. Validation SQL 注入 / XSS / 脏数据Injection / XSS / bad data 白名单校验 + 参数化查询Whitelist + parameterized SQL 5 漏洞扫描5. Scanning 已知后门与过期依赖Known vulns / old deps 每周扫一次,高危 72 小时内修Weekly scan, fix critical in 72h 优先级:输入验证 > 认证 > 限流 > CORS > 定期扫描Priority: validation > auth > rate limit > CORS > scanning WAF 是最后一道补丁,不是第一道防线;先把自己代码写干净WAF is a patch, not the first line; clean code first
独立サイトAPIの五層防御:認証、レート制限、CORS、入力検証、脆弱性スキャンの優先順位としきい値

独立サイトのAPIセキュリティ:認証、レート制限、CORS、入力検証、脆弱性対策

結論から言うと:独立サイトの外部APIの安全は、WAF一枚で守るものではなく、五つの層を重ねて初めて成立します。認証で身元を固定し、レート制限で連打を抑え、CORSでクロスドメインの穴を狭め、入力検証で不正データを遮断し、依存関係スキャンで定期的に裏口を掃除する。最も多い誤解は「HTTPSにすれば安全」というものです。HTTPSが防ぐのは盗聴だけで、リプレイ攻撃、大量呼び出し、SQLインジェクションは防げません。五層のうち最初に取り組むべきはWAFではなく入力検証です。これがデータベースを丸ごと抜かれるかどうかを直接左右します。

1. なぜ「HTTPSにした」だけではAPIは安全にならないのか

多くのサイト運営者はHTTPSを安全の代名詞ととらえ、ブラウザとサーバー間が暗号化されていればAPIは安心だと考えます。これが最初の認識ミスです。HTTPSが解決するのは「通信路上で盗み聞きされる」ことで、「正規の身元を悪用して連打される」「悪意あるスクリプトでログインAPIを大量に叩かれる」「リクエストにSQLを仕込まれてテーブルを抜かれる」ことは解決できません。

ここでの直感に反する判断はこうです。実際に独立サイトで事故が起きる原因は、ほぼすべてアプリケーション層の脆弱性であり、トランスポート層ではありません。データベースの抜き取り、削除、APIの連打によるダウンは、九割が入力未検証、認証の甘さ、レート制限の未設定に起因します。WAFは既知の攻撃パターンの一部は防げますが、自社のビジネスロジックに生じた穴は防げません。これはサイトが攻撃を受けた後の振り返り結論と一致します。まずコードを整理し、その後に強化を考えるべきです。

五層の防御はそれぞれ役割が異なり、一つ欠けるとその種類の攻撃が直接貫通します。次の表で、各層が「何を防ぎ、欠けるとどうなるか」を一度に整理します。

防御層 防ぐ攻撃 典型的な実装 漏れたときの結果
認証 匿名呼び出し、他人の身元のなりすまし APIキー、JWT、OAuth2 データAPIを誰でも直接取得できてしまう
レート制限 ブルートフォース、APIの大量連打 IP/キー単位のスライディングウィンドウ ログインAPIへのクレデンシャルスタッフィング、データベースの抜き取り
CORS 悪意あるサイトからのクロスドメインデータ読み取り オリジンホワイトリスト ユーザーのログイン状態で第三者サイトにデータを読まれる
入力検証 SQLインジェクション、XSS、不正データの書き込み ホワイトリスト検証+パラメータ化クエリ データベース全体の抜き取り、管理画面へのXSSによるセッションハイジャック
脆弱性スキャン 既知の裏口、古い依存関係 依存関係スキャン+定期的な脆弱性診断 公開EXPのある古いプラグインを使っている

2. 認証:三つの方式の選び方と、鍵の管理方法

独立サイトの外部APIは二種類に分かれます。フロントエンドのブラウザが使うもの(ログイン状態、フォーム送信)と、外部システムとの連携に使うもの(Webhook、サードパーティ同期)です。この二種類では使う認証方式が異なるので、混同しないでください。

フロントエンドのログイン状態にはJWTを使います。トークンに有効期限を持たせ、デフォルトは2時間。期限切れはrefresh tokenで更新します。外部システムとの連携には長期のAPI Keyを使い、URLパラメータではなくリクエストヘッダーに入れます。URLはログやブラウザ履歴に残るためです。OAuth2は「ユーザーが第三者に自分の代理アクセスを許可する」必要がある場合だけ導入します。個人の独立サイトでは90%のケースで不要であり、自分で複雑さを増やすだけです。

判断基準はこうです。そのAPIが自分のフロントエンド専用ならJWTで十分です。取引先のプログラムから呼ばれる場合は独立したAPI Keyを発行し、取引先ごとにKeyを分けて作成します。そうすればいつでも個別に失効できます。鍵は四半期ごとに1回ローテーションし、切り替え時は新旧のKeyを7日間併存させ、連携先が一気に止まらないようにします。

認証方式 適用シーン トークン有効期限 ローテーション / 失効
セッションCookie 従来型のフォームログイン管理画面 ブラウザセッション ログアウトで失効
JWT フロントとバックエンドを分離、フロントがAPIを呼ぶ アクセストークン2時間 refreshは7日、サーバー側でブラックリスト管理
APIキー 外部システム、Webhookコールバック 長期、取引先ごとに発行 四半期ごとにローテーション、個別失効可
OAuth2 第三者アプリがユーザーに代わって認可 短期access + refresh ユーザーがいつでも認可を取り消せる

三、レート制限:誰を単位に制限し、しきい値をいくつにするか

レート制限で最も多い失敗は「サイト全体で1つのしきい値」にすることです。ログインAPIと商品一覧APIでは正常時の呼び出し頻度が桁違いなので、同じしきい値では実際のユーザーを誤って制限するか、攻撃を止められないかのどちらかになります。正しいやり方は、APIごとにレベル分けし、単位ごとに制限することです。

レート制限は3つの単位を重ねます。IP単位で単独の攻撃者が帯域を使い切るのを防ぎ、アカウント単位で漏洩したパスワードリストの総当たりを防ぎ、API Key単位で特定の取引先プログラムの暴走を防ぎます。しきい値は具体的な数字で示します。次の表は独立サイトでよくあるAPIの初期値で、公開後に実際のトラフィックを見て調整します。

シナリオ例:ログインAPIへのパスワードリスト攻撃。IP単位で毎分10回、アカウント単位で毎分5回の失敗に設定し、5分間連続で超過したらそのIPを1時間ブロックします。これは単に「ログイン失敗5回でアカウントロック」とするより効果的です。攻撃者は同じパスワードで別のアカウントを試すため、単一アカウントのしきい値では防げないからです。フォーム関連のスパム対策は、問い合わせフォームの信頼性のスパム対策を参考にしてください。

API種別 制限単位 初期しきい値 超過時の動作
ログイン / パスワード再設定 IP + アカウント 10回/分 1時間の一時ブロック
問い合わせフォーム送信 IP 3回/分 CAPTCHAを表示
公開商品一覧 IP 60回/分 429を返す
外部API連携 APIキー 契約で定めたQPS 429 + 連携先に通知
サイト内検索 セッション 20回/分 429を返す

四、CORS:いつ有効にすべきか、どこまで許可するか

CORS(クロスオリジンリソース共有)はブラウザが備えている保護機能です。既定では、あなたのページのスクリプトは他ドメインのAPIの戻り値を読めません。これは「有効にすると危険」ではなく、「設定を間違えると危険」なのです。最も多いミスは、手間を省いて Access-Control-Allow-Origin: * と書き、さらに Allow-Credentials: true を組み合わせるケースです。これはクロスオリジンの入口をネット全体に開放するのと同じです。

判断のルールはこうです。あなたのAPIを自社のフロントエンドだけが呼ぶなら、CORSの許可リストには自社ドメインだけを入れてください(wwwありとwwwなしの両方)。* は加えません。第三者のフロントエンドが呼ぶ場合は、ドメインを1つずつ追加します。*.yourdomain.com のような正規表現によるあいまいな書き方は避けてください。サブドメインが取得されたり攻撃されたりした時点で、そこが攻撃対象になってしまいます。

Cookieを使わない純粋な公開API(商品一覧など)は、そもそもCORSの認証情報を有効にする必要がありません。ブラウザのシンプルリクエストへの制限はそこまで厳しくないので、設定を1つ減らせばリスクも1つ減ります。認証情報とクロスオリジンデータのコンプライアンスの境界線は、次を参照してください。海外展開サイトのコンプライアンス基盤Cookieとデータの越境に関する説明です。

シナリオ Allow-Origin の設定 Allow-Credentials 安全性
自社フロントエンドのみが呼ぶ 許可リストを自社ドメインに限定 true(ログイン状態が必要) 安全性
公開の商品データAPI 設定しない、または * false 安全性
手間を省いて * と認証情報 true を書く * true 危険。必ず修正
正規表現 *.yourdomain.com あいまいマッチ true 危険。サブドメインを攻撃された時点で突破される
複数の提携先フロントエンド ドメインを1つずつ許可リストに追加 true 安全。不要な項目は定期的に削除

五、入力検証と脆弱性対策:不正なデータを入口で防ぐ

入力検証は、この5層のうち一人チームが最も見落としやすく、影響が最も重い層です。原則はただ一つ。フロントエンドや外部APIから来るデータは決して信用しないこと。すべての入力値に許可リスト方式の検証を行います。型、長さ、形式、列挙値が合わなければそのまま拒否し、「サニタイズしてから使い続ける」ことはしないでください。

SQLインジェクションはパラメータ化クエリで根本から防ぎ、SQL文字列を自分で連結しないでください。XSSは出力時のエスケープで根本から防ぎます。ユーザーが送信した内容はデータベースに保存する時点ではエスケープせず、ページに出力する時点でコンテキストに応じてエスケープします(HTMLコンテキスト、JSコンテキスト、URLコンテキストではエスケープ規則が異なります)。ファイルアップロードは拡張子の許可リストを設け、ファイル名を変更し、Webディレクトリ以外に保存します。これらはOWASP Top 10の基本項目であり、何ら「高度なテクニック」はありません。

脆弱性スキャンは決まったリズムで実施します。依存関係のロックファイルは毎週自動でスキャンし、高危険度(CVEスコア9以上)が見つかれば72時間以内にアップグレードするか、その機能を一時停止します。サイト全体は毎月1回パッシブスキャンを行い、結果と照らし合わせて期限切れのプラグインを整理します。監視アラートの連携方法は、次を参照してください。サイト監視とアラート。技術スタック自体のセキュリティ上のトレードオフは、次と照らし合わせてください。環形山テックスタック。

対策項目 やり方 頻度 / しきい値 レッドライン
入力値の検証 型+長さ+許可リストの列挙値 すべてのAPIで必須 フロントエンドだけでの検証は禁止
SQLインジェクション パラメータ化クエリ / プリコンパイル コードレビュー必須確認項目 SQL文字列連結の禁止
XSS 出力は文脈に応じてエスケープ すべてのユーザー出力箇所 リッチテキストを未サニタイズで raw 出力するのを禁止
ファイルアップロード 拡張子ホワイトリスト+リネーム アップロードAPIに必須設定 アップロードディレクトリでのスクリプト実行を禁止
依存関係の脆弱性スキャン ロックファイルを自動スキャン 週に一度 深刻度9以上の高危険度は72時間以内に修正

FAQ よくある質問

自社サイトはWAFを入れないと安全とは言えないのか?
そうとは限りません。WAFは最後の補強であって、シグネチャで既知の攻撃を防ぐもので、自分の業務ロジックから生じるインジェクションや権限昇格は防げません。少人数チームなら、まず5層のうち前4層を固めてください。認証、レート制限、CORS、入力検証です。そのうえでCDN付属のWAFを検討します。順序を逆にすると、隙間風の入る窓に立派な鍵をかけるようなものです。
JWTとAPIキーはどちらを使うべき?
呼び出し元によります。自分のフロントエンドブラウザから自分のAPIを呼ぶならJWTで、2時間で失効させrefresh tokenを併用します。外部システムやパートナーのプログラムから呼ばれるなら長期APIキーを使い、リクエストヘッダーに載せ、パートナーごとに発行して個別に失効させます。マシン間通信にJWTを使わないでください。長期APIキーをブラウザ側に渡すのもやめてください。
レート制限のしきい値はどう決めれば正常なユーザーを誤って弾かない?
エンドポイントごとに段階を分けて始めます。ログインは毎分10回、フォームは毎分3回、公開リストは毎分60回。公開後、実際のトラフィックで2週間運用してから調整します。原則は、実際のピークより倍ほど緩めにしても、正常なユーザーを止めないことです。本当に危険なエンドポイント(ログイン、パスワード再設定)は誤検知を恐れず厳しくします。超過時はまず429を返し、連続超過なら一時的にIPをブロックします。
CORSで Access-Control-Allow-Origin: * と書くと何が問題?
* 単体なら公開の読み取り専用APIでは大きな問題ではありません。しかし Allow-Credentials: true と同時に設定すると、任意の第三者サイトがユーザーのログイン状態を伴ってあなたのAPIを読めることになり、ブラウザが明確に禁止する高危険な組み合わせです。正しい方法は Allow-Origin を自分のドメインに正確に指定することです。wwwありとなしの両方を含め、クロスドメイン連携が必要なときは個別にホワイトリストへ追加します。
入力検証をフロントエンドでやっているのになぜバックエンドでも必要なのか?
フロントエンドの検証は体験の最適化にすぎず、セキュリティ境界ではありません。誰でもブラウザを迂回してスクリプトやPostmanでAPIを直接叩けるので、フロントの検証は完全に飛ばされます。バックエンドでは各入力パラメータに対して型、長さ、ホワイトリスト列挙の検証をやり直し、合わなければ拒否します。フロントは表示を減らせても、バックエンドは1層も省けません。
脆弱性スキャンはどのくらいの頻度でやればいい?
依存関係のスキャンは週1回、CIに組み込んで自動実行し、CVSSスコア9以上の高危険度が見つかったら72時間以内にアップグレードするか、その機能を一時停止します。サイト全体のパッシブスキャンは月1回、期限切れプラグインと公開EXPの一致を重点的に確認します。問題が起きてからスキャンするのではなく、個人運営のチームは半年以上更新していないプラグインでつまずきがちです。

最後に

独立系サイトのAPIセキュリティの本質は、ツールを積み上げることではなく層に分けることです。どこかの層が突破されても、次の層が食い止めます。単一の防御が最も脆く、WAFをどれだけ立派に設定しても入力検証がなければ、インジェクションはそのままデータベースに届きます。5層のうち優先すべきは入力検証と認証で、この2層は投資が最も小さく効果が最も大きいです。レート制限とCORSは設定作業で半日あれば整い、脆弱性スキャンは週1回の自動実行タスクにします。

実装は3ステップです。第一に、すべての外部インターフェースに認証を追加し、長期キーは取引先ごとに分けて発行します。第二に、ログインとフォームのインターフェースに段階的なレート制限を設定し、公開インターフェースはまず緩めにします。第三に、各入力パラメータをバックエンドでホワイトリスト検証し、依存関係スキャンを週次タスクに組み込みます。この3ステップを終えれば、あなたのインターフェースは「たまに試される」状態になり、「門戸を開け放した」状態ではなくなります。日々のメンテナンスのペースはこちらを参照してください。公式サイト保守期間一緒に並べよう。

覚えておきたい一言。APIセキュリティは一枚の壁ではなく、五つの扉です。どの扉も鍵をかけなければならず、一つでも漏れれば残りの四つは形だけになります。

环形山
环形山 クレーター専門家

公式アカウント · 環形山 Crater

環形山(Crater)は、WordPress独立サイト開発+Google SEO+GEO全域成長に特化した海外展開支援会社で、スマートハードウェア、産業機器、SaaS、新エネルギーなどの分野を手がけています。

プロダクト能力方法論ホワイトペーパー業界レポート
965件のシェア
78件のナレッジベース