先に要点
Web開発を学び始めると、フロントエンド、バックエンド、クライアントサイド、サーバーサイドという言葉が何度も出てきます。どれも「画面側」「裏側」という雰囲気では分かるものの、会話の中で混ざりやすい言葉です。
最初に結論を書くと、次のように分けるとかなり整理しやすくなります。
- フロントエンド: 利用者が見る画面や操作部分を作る領域
- バックエンド: アプリの裏側でデータ処理や業務ロジックを扱う領域
- クライアントサイド: 利用者のブラウザや端末側で動く処理
- サーバーサイド: サーバー側で動く処理
この記事では、この4つの意味を「担当領域」と「処理が動く場所」に分けて整理し、さらに境界を勘違いしたときに実際どんな事故が起きるのかを、具体的なコマンドと修正手順つきで見ていきます。
まず全体像
4つの言葉は、同じ軸で並んでいるわけではありません。ここを押さえると、一気に分かりやすくなります。
| 言葉 | 主に表すもの | ざっくり言うと | 例 |
|---|---|---|---|
| フロントエンド | 担当領域 | 利用者が触る画面側 | 画面、フォーム、ボタン、状態管理 |
| バックエンド | 担当領域 | アプリの裏側 | API、認証、DB、業務ロジック |
| クライアントサイド | 処理場所 | 利用者の端末側 | ブラウザで動くJavaScript |
| サーバーサイド | 処理場所 | サービス提供側のサーバー | PHPやLaravelで動く処理 |
つまり、フロントエンドとバックエンドは「何を担当するか」の話です。クライアントサイドとサーバーサイドは「どこで処理が動くか」の話です。
ここで強調しておきたいのは、4つを2軸で見ると、フロントエンドの仕事がサーバーで動くこともあれば、バックエンド的なロジックがうっかりブラウザに出てしまうこともある、という点です。後半の事故例は、まさにこの「担当領域」と「処理場所」を同一視したときに起きます。
フロントエンドとは
フロントエンド は、WebアプリやWebサイトで利用者が直接見る画面や操作部分を作る領域です。HTML、CSS、JavaScript、React、Vue、フォーム、ボタン、入力エラー表示、画面遷移などが関係します。
たとえば、次のような仕事はフロントエンドに含まれやすいです。
- 画面のレイアウトを作る
- ボタンやフォームを実装する
- APIから受け取ったデータを画面に表示する
- 入力中のエラーを分かりやすく出す
- ローディング状態を表示する
- スマホでも崩れないようにする
- キーボード操作やアクセシビリティを考える
見た目だけではなく、利用者が迷わず操作できるようにすることもフロントエンドの大事な役割です。
重要なのは、フロントエンドのコードは「最終的にブラウザへ配られる」前提だということです。ビルドして配信した時点で、JavaScript もソースに埋め込んだ文字列も、利用者が DevTools で全部読めます。フロントエンドに置いてよいのは「見られても困らない情報」だけ、という感覚が後で効いてきます。
バックエンドとは
バックエンド は、Webアプリやサービスの裏側でデータ処理、認証、業務ロジック、APIなどを扱う領域です。利用者が直接見る画面ではなく、画面から送られたリクエストを受け取り、必要な処理をして結果を返す側です。
たとえば、次のような仕事はバックエンドに含まれやすいです。
バックエンドは、見えにくい部分ですが、アプリの正確さ、安全性、保守性に強く関係します。とくに「秘密鍵を握る」「最終的な権限を判断する」処理は、利用者の手が届かないバックエンドにあるからこそ信頼できます。ここがブラウザ側に漏れると、後述のとおり一気に事故になります。
クライアントサイドとは
クライアントサイド は、利用者のブラウザやスマホアプリなど、サービスを使う側の端末で動く処理を指します。Webでは、ブラウザで動くJavaScriptが代表例です。
たとえば、次のような処理はクライアントサイドです。
- ボタンを押したらメニューを開く
- 入力中に文字数を数える
- ブラウザ上で画面の一部を書き換える
- APIを呼び出して結果を表示する
- タブやモーダルを切り替える
- 地図やグラフをブラウザ上で操作する
クライアントサイド処理は、操作感をよくしやすい一方で、利用者の端末で動くため、秘密情報を置く場所としては向きません。管理者だけが使えるキー、決済の確定、権限の最終判断などは、基本的にサーバー側で扱うべきです。理由はシンプルで、クライアントサイドのコードと値は「全部利用者に見えるし、書き換えられる」からです。
サーバーサイドとは
サーバーサイド は、Webサーバーやアプリケーションサーバーなど、サービス提供側の環境で動く処理を指します。PHP、Java、Python、Ruby、Go、Node.jsなどで書かれることが多いです。
たとえば、次のような処理はサーバーサイドです。
- ログインしてよいユーザーか確認する
- データベースから記事を取得する
- 注文データを保存する
- HTMLを生成してブラウザに返す
- APIとしてJSONを返す
- メールを送る
- 決済サービスと通信する
- アクセスログを残す
サーバーサイドは、利用者から直接見えにくい場所で動きます。そのため、権限確認、データ更新、秘密鍵の利用など、信頼できる環境で行うべき処理を担当しやすいです。
4つの関係をリクエストの流れで見る
Webアプリの動きを、記事一覧ページを開く例で見てみます。
この流れの中で、フロントエンドは「利用者が見る画面や操作体験」を担当します。バックエンドは「データ取得、保存、認証、API」などを担当します。
一方、クライアントサイドは「ブラウザ側で動く処理」、サーバーサイドは「サーバー側で動く処理」です。同じ画面表示でも、どこで HTML を作るかによって、クライアントサイド寄りにもサーバーサイド寄りにもなります。境界線は固定ではなく、3 のステップ(サーバー)で作るか 6 のステップ(ブラウザ)で作るかで動く、と捉えると正確です。
よくある組み合わせ
実務では、次のような組み合わせがよくあります。
Next.js やNuxtのように、フロントエンド寄りの技術で サーバーサイドレンダリング も扱う構成です。境界が少し混ざります。
モバイルアプリ + API
スマホアプリがクライアント、APIサーバーがバックエンドです。画面はアプリ側、認証やデータ保存はサーバー側に寄ります。
このように、フロントエンドとバックエンドはチームや役割の話として使われることが多く、クライアントサイドとサーバーサイドは実行場所の話として使われることが多いです。
「フロント=クライアント」の思い込みが招く事故
ここが今回いちばん伝えたい実務的な話です。「フロントエンド = クライアントサイド = 自分の担当だから何を置いてもいい」と考えてしまうと、本来サーバーサイドにあるべき秘密や判断をブラウザに出してしまいます。代表的な2つの事故を、現象→原因→確認→回避の形で見ていきます。
事故1: 決済の秘密鍵をフロントの環境変数に入れる
| 項目 | 内容 |
|---|---|
| 現象 | Stripe決済を実装し、数日後に身に覚えのない返金やテスト課金が走る。Stripeから「秘密鍵が公開されている可能性がある」という警告メールが届く。 |
| 原因 | 「フロントから決済APIを叩きたい」と考え、シークレットキー(sk_live_ で始まるキー)を NEXT_PUBLIC_STRIPE_SECRET_KEY や VITE_STRIPE_SECRET_KEY という名前の環境変数に入れた。Next.jsの NEXT_PUBLIC_、Viteの VITE_ という接頭辞は「ブラウザに渡してよい変数」を意味し、ビルド時にJSバンドルへ値が直接埋め込まれる。つまり秘密鍵が誰でも読めるファイルに焼き込まれた。 |
| 確認手順 | ビルド成果物の中を検索する。grep -r "sk_live_" dist/ や grep -rn "STRIPE_SECRET" .next/static でヒットしたらアウト。ブラウザのDevToolsでSourcesタブを開き、バンドルされたJSを sk_live_ で全文検索しても確認できる。 |
| 回避 | まずStripeダッシュボードで露出したキーを即ローテート(無効化して再発行)する。次にシークレットキーは NEXT_PUBLIC_ や VITE_ を付けない環境変数に置き、サーバー側のAPIルート(例: /api/checkout)からのみ使う。ブラウザに渡してよいのは公開可能キー(pk_live_ で始まるキー)だけ。最後にgit履歴とCIログにも残った旧キーを確認して消す。 |
ポイントは、シークレットキー(sk_)を握ったらアカウント上で課金・返金・顧客データ取得まで何でもできてしまう、という点です。これは典型的なバックエンド・サーバーサイドの仕事であり、見た目上「フロントから呼びたい」だけの理由でクライアントに出してはいけません。公開可能キー(pk_)はそもそもトークン化など限られた操作しかできないよう設計されているので、ブラウザに置いても被害が限定されます。同じ「キー」でも、置いてよい場所がまったく違います。
事故2: LLM/外部APIキーをブラウザに直書きする
同じ構造のミスは、生成AIのAPIキーでも頻発します。
| 項目 | 内容 |
|---|---|
| 現象 | 個人開発のチャットアプリを公開したら、翌月の請求が想定の何倍にも膨らむ。自分は使っていない時間帯に大量のAPI呼び出しが記録される。 |
| 原因 | ReactのコンポーネントからAPIキーを直接 fetch のヘッダに入れた。VITE_OPENAI_API_KEY のようにブラウザへ渡る変数名にしたため、キーがJSバンドルに焼き込まれ、誰でもネットワークタブやSourcesから盗める状態になった。盗んだ第三者がそのキーで自由にAPIを叩いた。 |
| 確認手順 | DevToolsのNetworkタブで自分のアプリのリクエストを開き、Authorization ヘッダにキーが平文で乗っていないか見る。乗っていれば、それはブラウザから送られている=露出している。grep -rn "VITE_.*KEY" dist/assets でも焼き込みを確認できる。 |
| 回避 | 露出したキーを即無効化する。そのうえで、ブラウザからは自前のサーバーサイドエンドポイント(例: /api/chat)を呼ぶだけにし、APIキーはサーバー側だけが保持してそこから外部APIへ中継する。ついでにサーバー側でレート制限や利用上限を入れておくと、万一の被害も抑えられる。 |
事故3: 権限チェックをクライアントだけで済ませる
3つ目は鍵ではなく「判断」を間違える例です。
- 現象: 一般ユーザーが管理者用の操作(他人のデータ削除など)を実行できてしまう。
- 原因: 「管理者のときだけ削除ボタンを表示する」というクライアントサイドの分岐だけで権限を守ったつもりになっていた。ボタンを隠すのはUIの都合であって、サーバー側の
DELETE /api/users/123自体は誰でも叩けるまま放置されていた。攻撃者はボタンを使わず、DevToolsやcurlで直接APIを呼ぶ。 - 確認手順: 一般ユーザーのトークンで、管理者専用のはずのエンドポイントを
curlやDevToolsから直接叩いてみる。200が返り処理が通ってしまえば、それは「クライアントで隠しただけ」の状態。 - 回避: 権限の最終判断は必ずサーバーサイド(バックエンド)で行う。クライアント側のボタン制御はあくまで利便性のための補助で、セキュリティ境界ではない、と切り分ける。
この3例に共通するのは、「フロントエンドの担当だから」とクライアントサイドに秘密や判断を持たせてしまった点です。担当領域(フロント/バック)と処理場所(クライアント/サーバー)は別の軸であり、秘密と最終判断は処理場所としてのサーバーサイドに置く、という原則を分けて覚えるのが事故防止の核心です。
混同しやすいポイント
フロントエンド = クライアントサイド?
かなり近いですが、完全に同じではありません。フロントエンドは画面側の担当領域です。クライアントサイドはブラウザや端末側で動く処理です。
たとえば、SSR では、フロントエンドの画面をサーバー側で生成することがあります。この場合、フロントエンドの仕事なのに、処理場所はサーバーサイドにも関わります。逆に、上の事故例のように「フロントだから」とクライアントに秘密を置くと破綻します。担当領域とは別に、処理場所として安全かを必ず分けて考えてください。
バックエンド = サーバーサイド?
これもかなり近いですが、完全に同じではありません。バックエンドは API、認証、DB、業務ロジックなどの裏側の領域です。サーバーサイドはサーバーで動く処理です。
サーバー側で HTML を生成するだけの処理はサーバーサイドですが、会話によっては「バックエンド」より「サーバーサイドレンダリング」と呼んだ方が分かりやすいこともあります。
JavaScriptはフロントエンド専用?
専用ではありません。JavaScriptはブラウザで動くためフロントエンドの中心技術ですが、Node.jsを使えばサーバーサイドやバックエンドにも使われます。
PHPはバックエンド専用?
PHPはサーバーサイドでよく使われますが、HTMLテンプレートを返すWebサイトでは画面表示にも深く関わります。つまり、言語名だけでフロントエンドかバックエンドかを完全に決めるのは少し雑です。
初心者はどう覚えるとよいか
最初は、次の2軸で覚えるのがおすすめです。
| 軸 | 対になる言葉 | 見方 |
|---|---|---|
| 担当領域 | フロントエンド / バックエンド | 誰が何を作るか |
| 処理場所 | クライアントサイド / サーバーサイド | どこで処理が動くか |
会話や設計で迷ったら、次のように言い換えると分かりやすいです。
- それは画面側の話か、裏側の話か
- その処理はブラウザで動くのか、サーバーで動くのか
- その値はブラウザに焼き込まれても困らないか(秘密鍵は絶対NG)
- その判断を利用者の端末に任せて安全か
- APIで分けるのか、サーバーでHTMLを返すのか
この観点を確認できると、Webアプリの構成がかなり見えやすくなり、秘密鍵や権限まわりの事故も避けやすくなります。
フロントエンドとバックエンドの違いに関するよくある質問
Q. フロントエンドとクライアントサイドは同じですか?
A. ほぼ同じですが、ニュアンスが違います。フロントエンドは「UIと画面側の役割全般」、クライアントサイドは「利用者の端末で実行される処理」を強調する用語です。文脈で使い分けます。
Q. Next.js はフロントエンドですか、バックエンドですか?
A. 両方です。SSR/SSGでサーバー側の処理も担い、Reactコンポーネントでクライアント側UIも作ります。フルスタックフレームワークという位置づけです。
Q. 秘密鍵をフロントに置いてはいけないのはなぜですか?
A. フロントエンドのコードはビルド後にブラウザへ配られ、JavaScriptも埋め込まれた文字列も利用者が全部読めるからです。Next.jsの NEXT_PUBLIC_ やViteの VITE_ 付き変数はバンドルへ焼き込まれるので、シークレットキーをこの名前に入れると即露出します。秘密鍵はサーバーサイドだけで保持してください。
Q. APIキーをフロントに置いてしまった場合、どう直しますか?
A. まず発行元(Stripeやクラウドサービス)でそのキーを無効化・再発行(ローテート)します。アプリ側ではキーを NEXT_PUBLIC_/VITE_ なしの変数に移し、サーバー側のAPIルートからのみ使い、ブラウザはそのルートを呼ぶだけにします。git履歴やCIログに残った旧キーも消します。
Q. クライアント側で権限チェックをすれば十分ですか?
A. 不十分です。ボタンを隠すのはUIの都合で、セキュリティ境界ではありません。攻撃者はDevToolsやcurlでAPIを直接叩けるため、権限の最終判断は必ずサーバーサイドで行ってください。
Q. フルスタックエンジニアは現実的ですか?
A. 個人開発・小規模案件なら現実的、大規模では難しいです。中規模なら「フロント中心 + バック少し」「バック中心 + フロント少し」のT字型エンジニアが増えています。
Q. どちらから学ぶべきですか?
A. 興味次第ですが、画面に動きを付ける楽しみを得やすいフロントエンドが入りやすいです。バックエンドは仕組みを設計したい興味がある人向けです。ただしどちらを選んでも、上記の「秘密と判断はサーバー側」という境界は最初に身につけておくと事故を防げます。
参考リンク
- MDN: Glossary of web terms
- MDN: Server-side rendering (SSR)
- MDN: Client-side Rendering (CSR)
- Stripe: API keys
- Vite: Env Variables and Modes