こんにちは、TIMEWELLの濱本です。今日はテック関連のサービスご紹介です。
最近、vibe codingという言葉をよく耳にするようになりました。AIの力を借りて、プログラミング経験が浅くてもWebサイトやアプリを形にできる。Next.jsとVercelの組み合わせは、その手軽さとパフォーマンスの高さから、個人開発者を中心にどんどん広がっています。
ただ、手軽に作れるようになった分、つい後回しにしがちなのがセキュリティの話です。「個人開発だし、小さいサイトだし」と油断していると痛い目を見ます。情報漏洩やサイト改ざんが起きたとき、その責任を負うのは開発者自身。ユーザーの信頼は、一度失うと取り戻すのに途方もない時間がかかります。
今回は、Vercelを前提としたHP制作で「これだけはやっておくべき」セキュリティ対策を、具体的なコードも交えながら解説します。私自身、クライアントのサイトを構築する中で「ここは最低限押さえておかないとまずい」と感じたポイントを中心にまとめました。
そもそも、なぜセキュリティ対策が必要なのか
「自分のサイトは小さいから、攻撃者の標的にはならないだろう」。この考え方が一番危ない。
現代のサイバー攻撃の大半は、特定のサイトを狙い撃ちするものではありません。脆弱性のあるサイトをプログラムで片っ端から探し出し、自動で攻撃を仕掛けてくる。サイトの規模は関係なく、インターネットに公開されている時点で全てが標的になりえます。
個人開発者が直面しやすい脅威を整理するとこうなります。
| 脅威の種類 | 起きること |
|---|---|
| サイト改ざん | トップページが書き換えられる。フィッシングサイトへの誘導リンクを埋め込まれることも |
| フォームスパムやボット攻撃 | お問い合わせフォームに意味不明な文字列や広告が大量に届き、本物の問い合わせが埋もれる |
| APIキーの漏洩 | ソースコードに書いてしまったAPIキーが流出し、第三者に不正利用される。高額請求が来るケースもある |
| DDoS攻撃 | 大量アクセスでサーバーがダウンし、サイトが表示不能に |
直接的な被害だけでなく、二次被害も深刻です。サイトが改ざんされれば訪問者からの信頼は地に落ちる。スパム対応に追われれば本来の業務が止まる。個人情報が流出すれば、損害賠償の話にもなりかねません。
セキュリティ対策は技術的な話であると同時に、ビジネスリスクの話でもあります。
Vercelが標準で守ってくれていること
セキュリティ対策と聞くと身構えてしまうかもしれませんが、Vercelを使っている時点で、実はかなりの部分が自動的にカバーされています。まずはその恩恵を正しく理解しておきましょう。
HTTPS/SSLの自動化
WebサイトのURLが https:// で始まっているかどうか。この「s」はSecureの略で、ブラウザとサーバー間の通信がSSL/TLSで暗号化されていることを意味します。第三者によるデータの盗聴や改ざんを防ぐ基本中の基本であり、Googleの検索順位にも影響する必須要件です。
通常、SSL証明書の取得や更新には手間がかかりますが、Vercelではカスタムドメインを設定するだけで無料のSSL証明書が自動発行され、更新も勝手にやってくれます。証明書の管理を意識する必要がそもそもない。これは地味にありがたいポイントです。
DDoS攻撃からの保護
DDoS攻撃は、大量のコンピューターから標的のサーバーに一斉にアクセスを送りつけ、サービスを停止に追い込む手法です。個人開発のサイトでも標的になることがあります。
Vercelは全プランでプラットフォームワイドなDDoS対策を標準提供しています。世界中に分散されたエッジネットワークが異常なトラフィックを検知し、自動でブロックしてくれる。特別な設定は不要です。
保管データの暗号化
Vercelのインフラ上で保管されるデータは、AES-256で暗号化されています。米国政府も採用する暗号化規格で、仮にデータが物理的に盗まれても解読は極めて困難です。
こうしたインフラレベルの保護があるからこそ、私たちは安心してアプリケーション開発に集中できる。ただし、ここから先は「自分で設定しないと守ってもらえない」領域に入ります。
Vercel Firewallを使いこなす
Vercelの標準DDoS対策に加えて、もう一段階踏み込んだ防御壁を構築できるのがVercel Firewall、特にWAF(Web Application Firewall)の機能です。
たとえるなら、標準のDDoS対策が国境を守る軍隊だとすれば、WAFはあなたのビルの入り口に立つ警備員。誰を通して誰を追い返すか、細かいルールを自分で決められます。
WAF機能は全プランで利用可能で、ダッシュボードの Your Project から Settings、Firewall と進めば設定画面が開きます。押さえておきたい機能は4つ。
IPブロッキング
特定のIPアドレスからのアクセスを完全に遮断する機能です。アクセスログを見ていて、同じIPから何度もログイン試行が来ているような場合、そのIPを名指しでブロックできます。
Country Blocking機能を使えば、国単位でのブロックも可能です。日本国内向けのサービスなのに海外からのスパムが多い、という場合に有効です。
カスタムルール
IPブロッキングよりも柔軟なアクセス制御ができます。「もしこの条件に合致したら、このアクションを実行する」というルールを自由に作れる仕組みです。
たとえば、管理画面(/adminなど)へのアクセスを自宅やオフィスのIPだけに限定する。特定の攻撃ツールが使うUser-Agentを持つアクセスをブロックする。こうした細かい調整ができるのがカスタムルールの強みです。
マネージドルールセット
「自分でルールを作るのは難しそう」という方も安心してください。Vercelのセキュリティ専門チームが作成・維持しているルール集が用意されています。
SQLインジェクションやXSS(クロスサイトスクリプティング)といった、よく知られた攻撃パターンに対応するルールがまとまっていて、ダッシュボードで有効にするだけで導入完了。正直、これを有効にしない理由がありません。
アタックチャレンジモード
全てのアクセスを「許可」か「ブロック」の二択で判断するのではなく、「ちょっと怪しいけど断定はできない」というアクセスにJavaScriptチャレンジを課す機能です。正規ユーザーを誤ってブロックするリスクを減らしつつ、ボットを効果的に排除できます。
まずはダッシュボードを開いて、どんな設定ができるか眺めてみてください。触ってみると意外とシンプルです。
フォームをスパムから守る3つの武器
Webサイトを公開すると、お問い合わせフォームがスパムの標的になるのはほぼ避けられません。ボットが広告や無意味な文字列を大量に送りつけてくる。
かつては「私はロボットではありません」のチェックボックスや、歪んだ文字を読ませる画像認証が主流でしたが、あれはユーザーにとってストレスでしかない。入力途中で面倒になって離脱されたら本末転倒です。
今はユーザーに何も操作させず、裏側で賢くボットを弾くアプローチが主流になっています。Next.js + Vercel環境で使える3つの武器を紹介します。
Honeypot(ハニーポット)
名前の通り「蜂蜜の壺」で、ボットをおびき寄せる罠です。仕組みはシンプルで、人間には見えないダミーの入力フィールドをフォームに仕込みます。
人間は見えないフィールドには何も入力しない。でもボットはプログラムでフォームの全フィールドを探し出し、律儀に全部埋めようとする。だから、見えないフィールドに値が入っていたら「これはボットだ」と判断できるわけです。
古典的な手法ですが、実装が簡単で、単純なボットには十分効きます。最初に入れておきたい第一の防衛線です。
フォームコンポーネントにダミーフィールドを追加し、CSSで画面外に飛ばして見えなくします。
// components/ContactForm.jsx
<form action={...}>
{/* 通常の入力フィールド */}
{/* Honeypot: CSSで見えなくする */}
<div className="hidden" aria-hidden="true">
<label htmlFor="honeypot">Leave this field empty</label>
<input type="text" id="honeypot" name="honeypot" tabIndex={-1} autoComplete="off" />
</div>
<button type="submit">送信</button>
</form>
/* global.css */
.hidden {
position: absolute;
left: -5000px;
opacity: 0;
}
サーバー側では、このフィールドに値が入っていないかチェックします。
// app/actions.js
'use server';
export async function submitForm(formData) {
// Honeypotチェック
if (formData.get('honeypot')) {
// ボットと判断。何もせず正常終了したように見せかける
return { success: true };
}
// 人間からのリクエストとして処理を続行
}
ポイントは、ボットと判断した場合もエラーを返さないこと。エラーを返すと「この対策が入っている」とボット側に知られてしまいます。
Vercel BotID
ハニーポットで単純なボットは防げますが、CSSを解釈して見えているフィールドにしか入力しない賢いボットも存在します。そこで使えるのがVercel独自のBotIDです。
BotIDはユーザーに一切の操作を求めない「見えないCAPTCHA」です。バックグラウンドでマウスの動き、キーボードの入力パターン、ブラウザ環境といった何千ものシグナルを機械学習で分析し、人間かボットかを判定します。
2つのレベルがあり、Basicは無料で使えるチャレンジ検証。Deep Analysisは有料ですが、PlaywrightやPuppeteerを使った高度なボットにも対抗できます。
ダッシュボードで Firewall の Rules から BotID Deep Analysis を有効にし、サーバー側のコードで checkBotId() を呼び出すだけです。
// app/actions.js
'use server';
import { checkBotId } from '@vercel/bot-id';
export async function submitForm(formData) {
try {
await checkBotId();
} catch (error) {
// ボットと判断された場合
console.error('Bot detected:', error);
return { success: false, message: 'Bot detection failed.' };
}
// 人間からのリクエストとして処理を続行
}
Google reCAPTCHA v3
3つ目はGoogleのreCAPTCHA v3。v2のチェックボックス式とは全く別物で、v3もユーザーの操作を一切妨げません。
reCAPTCHA v3は、ユーザーがサイトを回遊している間の行動を分析し、そのリクエストがどれくらい人間らしいかを0.0(ボットの可能性大)から1.0(人間の可能性大)のスコアで評価します。フォーム送信時にこのスコアを取得し、「0.5未満ならボットと見なす」といった閾値を設けることで、柔軟な対策が可能です。
実装には google-recaptcha-v3 ライブラリが便利です。
まず、Googleでサイトキーとシークレットキーを取得して環境変数に設定します。NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY はクライアント側、RECAPTCHA_V3_SECRET_KEY はサーバー側で使います。
フロントエンド側でフォーム送信時にトークンを取得します。
// components/ContactForm.jsx
import { GoogleReCaptchaProvider, useGoogleReCaptcha } from 'google-recaptcha-v3';
const FormComponent = () => {
const { executeRecaptcha } = useGoogleReCaptcha();
const handleSubmit = async (event) => {
event.preventDefault();
if (!executeRecaptcha) return;
const token = await executeRecaptcha('contactForm');
// フォームデータとtokenをServer Actionに渡す
};
return <form onSubmit={handleSubmit}>...</form>;
}
const ContactForm = () => (
<GoogleReCaptchaProvider reCaptchaKey={process.env.NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY}>
<FormComponent />
</GoogleReCaptchaProvider>
);
バックエンド側で受け取ったトークンをGoogleのAPIに送り、スコアを検証します。
// app/actions.js
'use server';
export async function submitForm(formData, token) {
const response = await fetch(
`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_V3_SECRET_KEY}&response=${token}`,
{ method: 'POST' }
);
const data = await response.json();
if (!data.success || data.score < 0.5) {
return { success: false, message: 'Bot detection failed.' };
}
// 人間からのリクエストとして処理を続行
}
個人的には、この3つを全部入れるのが理想だと考えています。Honeypotで雑なボットを弾き、BotIDで中級のボットを検知し、reCAPTCHA v3で高度なボットにも対応する。多層防御の考え方です。全部入れてもユーザーには何も見えないので、UXへの影響はゼロ。やらない理由がありません。
APIキーはどこに隠す?環境変数の正しい管理
vibe codingで外部サービスと連携するとき、ほぼ必ず登場するのがAPIキーです。データベース、AIサービス、メール送信サービス。どれもAPIキーという「秘密の鍵」を使ってアクセスします。
このAPIキーが漏洩すると、第三者があなたになりすましてサービスを不正利用できてしまう。データを盗み見られたり、大量のリクエストを送りつけられて高額な請求が来たり。個人開発のセキュリティ事故で最も多いのが、この「うっかり漏洩」だと感じています。
ソースコードに直接書くのは絶対NG
最もやってはいけないのが、APIキーをコードの中に直接書き込むこと。ハードコーディングと呼ばれる行為です。
// 絶対にやってはいけない例
const apiKey = 'sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// このコードをGitHubにプッシュすると...全世界にAPIキーが公開される
GitHubのリポジトリがプライベートであっても、コードを他者と共有する可能性がある限り、ハードコーディングは避けるべきです。APIキーの管理は環境変数で行います。
環境変数の設定方法
環境変数とは、アプリケーションの実行環境に保存される、コード本体とは分離された設定値のこと。コードの中ではAPIキーそのものではなく、環境変数の「名前」を参照します。
ローカル開発中は、プロジェクトのルートに .env.local ファイルを作成してAPIキーを記述します。
# .env.local
DATABASE_URL="postgres://..."
OPENAI_API_KEY="sk_..."
ここで絶対に忘れてはいけないのが、.env.local をGitの管理対象から外すこと。.gitignore ファイルに .env.local が含まれているか、必ず確認してください。Next.jsのプロジェクトを create-next-app で作成した場合はデフォルトで含まれていますが、念のため目視確認する癖をつけておくと安心です。
本番環境のVercelには、ダッシュボードの Settings から Environment Variables を開いて、同じ名前と値を登録します。こうすれば、ローカルでも本番でもコードを変えずにAPIキーを安全に扱えます。
NEXT_PUBLIC_ プレフィックスの罠
ここが一番怖い落とし穴です。
Next.jsでは、NEXT_PUBLIC_ で始まる環境変数はクライアント側のJavaScriptに埋め込まれ、ブラウザの開発者ツールから誰でも見られる状態になります。
Google AnalyticsのトラッキングIDのように、もともと公開前提の値を扱うための仕組みですが、この仕様を知らずにAPIキーに NEXT_PUBLIC_ をつけてしまう人が後を絶ちません。
| 環境変数の種類 | 公開範囲 | 用途の例 |
|---|---|---|
DATABASE_URL |
サーバー側のみ | データベース接続情報、APIキーなど秘匿すべき情報 |
NEXT_PUBLIC_GA_ID |
ブラウザにも公開 | Google AnalyticsのIDなど公開されても問題ない情報 |
秘密にすべき情報には NEXT_PUBLIC_ を絶対につけない。これはvibe codingを始めたら最初に叩き込んでおくべきルールです。
セキュリティヘッダーで防御をもう一段上げる
ここまでの対策に加えて、さらに防御力を高めたいならセキュリティヘッダーの設定です。サーバーからブラウザに応答を返す際に付与するHTTPヘッダーの一種で、ブラウザのセキュリティ機能を有効にして特定の攻撃を未然に防ぎます。
Next.jsでは next.config.js に記述するだけで、全ページのレスポンスにヘッダーを付与できます。
// next.config.js
const securityHeaders = [
{
key: 'X-Content-Type-Options',
value: 'nosniff'
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
}
];
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: securityHeaders,
},
];
},
};
それぞれのヘッダーが何を守ってくれるのか、簡単に説明します。
Content-Security-Policy(CSP)
XSS攻撃に対する強力な防衛線です。ページで読み込みを許可するリソースの提供元ドメインを厳密に指定できます。許可リストにないドメインからのスクリプトはブラウザがブロックしてくれるので、仮に悪意あるスクリプトが注入されても実行を防げます。
余談ですが、CSPの設定は最初から厳しくしすぎると、自分のサイトで使っているGoogle FontsやAnalyticsのスクリプトまでブロックしてしまうことがあります。まずは report-only モードで運用を始めて、意図しないブロックがないか確認しながら徐々に締めていくのが現実的です。
X-Frame-Options
あなたのサイトが他のサイトの iframe に埋め込まれることを防ぎます。悪意あるサイトが透明な iframe であなたのサイトを覆い、ユーザーに意図しないボタンをクリックさせる「クリックジャッキング」への対策です。SAMEORIGIN を指定すれば、自サイト内からの埋め込みだけを許可できます。
X-Content-Type-Options
nosniff を指定すると、ブラウザがサーバーの指示を無視してファイル形式を勝手に推測する(MIMEスニッフィング)のを防ぎます。テキストファイルをスクリプトとして誤実行するような攻撃を防止できます。
Strict-Transport-Security(HSTS)
一度HTTPSでアクセスしたユーザーに対して、以降は強制的にHTTPS接続するようブラウザに指示します。ユーザーが誤って http:// でアクセスしても、暗号化されていない通信が発生しません。
これらのヘッダーは一度設定すればあとは自動で効き続けるので、コストパフォーマンスの高い対策だと考えています。
公開前セキュリティチェックリスト
この記事で解説してきた内容を、サイトを公開する前に最終確認するためのチェックリストとしてまとめました。一つずつ確認して、安心してあなたのWebサイトを世界に届けましょう。
Vercel Firewall / WAF
- マネージドルールセットを有効にしたか?(Settings > Firewall > Managed Rulesets)
- 不審なIPアドレスや国からのアクセスをブロック設定したか?(IP Blocking / Country Blocking)
- 管理画面など、特定のパスへのアクセスをIPで制限したか?(Custom Rules)
フォームのスパム・Bot対策
- Honeypot(見えない入力フィールド)をフォームに実装したか?
- サーバー側でHoneypotフィールドに値が入っていたら処理を中断するロジックは入っているか?
- Vercel BotIDを有効にし、サーバー側で
checkBotId()を呼び出しているか? - Google reCAPTCHA v3を導入し、サーバー側でスコアを検証しているか?
機密情報の管理
- APIキーやデータベース接続文字列をソースコードに直接書いていないか?
- 全ての機密情報を
.env.localファイルで管理しているか? .gitignoreファイルに.env.localが含まれていることを確認したか?- Vercelのダッシュボードに本番環境用の環境変数を全て設定したか?
- 秘密にすべきAPIキーに
NEXT_PUBLIC_プレフィックスがついていないか、全環境変数を再確認したか?
セキュリティヘッダー
next.config.jsにセキュリティヘッダー(X-Content-Type-Options, X-Frame-Options, HSTS)を設定したか?- Content-Security-Policy(CSP)を
report-onlyモードからでも導入を検討したか?
依存関係の管理
npm auditやyarn auditを実行し、利用しているパッケージに既知の脆弱性がないか確認したか?- 発見された脆弱性に対して、パッケージのアップデートなどの対応を行ったか?
このチェックリストが、あなたの開発プロセスの一助となれば幸いです。
セキュリティは「やって終わり」ではない
ここまで、Vercel環境でのセキュリティ対策を6つの観点から解説してきました。
Vercelの標準保護、Firewall(WAF)によるアクセス制御、Honeypot・BotID・reCAPTCHA v3の多層的なBot対策、環境変数による機密情報の管理、セキュリティヘッダーによるブラウザレベルの防御。どれも一つひとつは決して難しい設定ではありません。
ただ、正直に言えば、セキュリティ対策は一度設定して終わりではありません。新しい脆弱性は日々発見されるし、攻撃手法も進化し続けています。フレームワークやサービスの公式ドキュメントを定期的にチェックし、知識をアップデートしていく姿勢が大切です。
こうした技術選定やセキュリティ設計に不安がある方は、TIMEWELLのWARPプログラムもぜひご検討ください。元大手DX・データ戦略の専門家が、Vercel + Next.jsをはじめとしたモダンな技術スタックでのサイト構築・運用を月次でサポートしています。セキュリティ対策の設計から実装まで、一緒に進められます。
最初から完璧を目指す必要はない。まずはこの記事で紹介した基本的な対策から一つずつ入れていけば、あなたのサイトの安全性は確実に上がります。安全なWebサイトは、ユーザーからの信頼を築くための土台。安心してvibe codingを楽しむために、今日できることから始めてみてください。
