CLOSE
MENU
Laravel 基礎学習/セキュリティリスクと対策

Laravel 基礎学習/セキュリティリスクと対策

Laravel のセキュリティ基礎を初心者向けに解説。XSS、CSRF、SQLインジェクションなどの代表的な攻撃手法と、Laravel による具体的な対策方法を学ぶ。

Web アプリで発生しやすいセキュリティリスク

Web アプリは、
インターネットを通じて不特定多数のユーザーからアクセスされる。

そのため、
セキュリティ対策が不十分な場合、
個人情報の漏洩やデータ改ざん、
不正ログインなどの被害につながる可能性がある。

特に Web アプリ開発では、
ユーザーから送信されたデータを扱う機会が多いため、
様々な攻撃手法への対策が必要となる。

代表的なセキュリティリスクとして、
以下のようなものがある。

Laravel には、
これらのリスクを軽減するための機能が多数用意されている。

ただし、
Laravel を使用しているだけで全ての攻撃を防げるわけではない。

まずは代表的なセキュリティリスクを理解し、
その後で一般的な対策方法や Laravel による具体的な対策を見ていこう。

XSS(クロスサイトスクリプティング)

XSS(Cross Site Scripting)は、
悪意のあるスクリプトを Web ページへ埋め込み、
他のユーザーのブラウザ上で実行させる攻撃。

例えば、
掲示板やコメント機能などで入力内容をそのまま表示している場合、
攻撃者が JavaScript を投稿できてしまう可能性がある。

攻撃例

<script>
alert('攻撃');
</script>

このようなコードがそのまま表示されると、
ブラウザは単なる文字列ではなく JavaScript として解釈して実行する。

実際の攻撃では、
alert のような単純な処理ではなく、
Cookie の窃取や不正サイトへの誘導などが行われることがある。

XSS が成立すると、
利用者になりすまして操作されたり、
個人情報が漏洩したりする危険があるため、
Web アプリ開発では特に注意が必要な攻撃のひとつ。

一般的な回避方法

XSS を防ぐためには、
ユーザーが入力した内容をそのまま HTML として出力しないことが重要。

例えば、

<script>alert('攻撃')</script>

が入力された場合でも、
JavaScript として実行されるのではなく、
単なる文字列として表示されるようにする必要がある。

この処理を
「HTML エスケープ」
と呼ぶ。

PHP の例

PHP では、
以下のように
htmlspecialchars()
を使用して HTML エスケープを行える。

echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');

このように出力すると、

<script>alert('攻撃')</script>

は JavaScript として実行されず、
単なる文字列として表示される。

ユーザー入力をそのまま画面へ表示しないことや、
信頼できない HTML を保存・表示しないことが重要な対策となる。

Laravel での対策

Laravel の Blade テンプレートでは、

{{ $comment }}

のように
{{ }}
を使用すると、
自動的に HTML エスケープが行われる。

例えば、
ユーザーが以下の内容を入力したとする。

<script>alert('攻撃')</script>

これを
{{ }}
で表示した場合、
JavaScript は実行されず、
文字列として表示される。

Laravel を使用する場合、
通常の画面表示では
{{ }}
を使用することで、
XSS のリスクを大幅に軽減できる。

一方で、
Blade の
{!! !!}
は HTML をそのまま出力するため、
ユーザー入力に対して安易に使用すると XSS の原因となる。

CSRF(クロスサイトリクエストフォージェリ)

CSRF(Cross Site Request Forgery)は、
ユーザーが意図しないリクエストを送信させる攻撃。

例えば、
ユーザーが銀行サイトへログインした状態で、
攻撃者が運営する別の Web サイトへアクセスしたとする。

そのサイト内に、
銀行サイトへ不正なリクエストを送信する仕組みが埋め込まれていた場合、
ユーザー本人が操作していなくても、
振込や設定変更などの処理が実行される可能性がある。

攻撃者はユーザーのパスワードを知る必要はなく、
「ログイン済みであること」を悪用するのが特徴。

攻撃イメージ

ユーザーがサービスへログイン

攻撃サイトへアクセス

攻撃サイトが
不正なリクエストを送信

サービス側が
正規ユーザーの操作だと誤認

意図しない処理が実行される

このように、
ユーザー本人は何もしていないにもかかわらず、
正規ユーザーとして処理が実行されてしまう。

そのため、
情報変更や退会処理、
送金処理などの重要な機能では、
CSRF 対策が必須となる。

一般的な回避方法

CSRF を防ぐためには、
リクエストが本当に自サイトから送信されたものかを確認する必要がある。

一般的には、
フォーム内へランダムなトークンを埋め込み、
サーバー側でその値を検証する方法が利用される。

トークンとは、
システムが発行する識別用の文字列のこと。

Web アプリでは、
認証やセキュリティ対策など、
様々な用途で利用される。

CSRF 対策で使用するトークンを
「CSRF トークン」
と呼ぶ。

サーバー側で受信したトークンを検証し、
一致しなければ処理を拒否することで、
外部サイトからの不正なリクエストを防ぐことができる。

PHP の例

PHP では、
以下のようにランダムな文字列を生成し、
セッションに保存しておくことで、
CSRF トークンとして利用できる。

<?php

session_start();

$_SESSION['csrf_token'] = bin2hex(random_bytes(32));

random_bytes()
は、
暗号学的に安全なランダムなバイト列を生成する関数。

bin2hex()
を使用することで、
フォームに埋め込みやすい文字列へ変換している。

生成した CSRF トークンは、
フォーム内の hidden フィールドへ埋め込む。

<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">

フォーム送信後は、
送信されたトークンと、
セッションに保存していたトークンを比較し、
一致する場合のみ処理を実行する。

Laravel での対策

Laravel には、
CSRF 対策機能が標準で用意されている。

POST、
PUT、
PATCH、
DELETE などのリクエストでは、
CSRF トークンの送信が必要となる。

Blade テンプレートでは、
フォーム内に
@csrf
を記述する。

@csrf

@csrf
を記述すると、
Laravel が自動で CSRF トークンを生成し、
フォームへ埋め込む。

フォーム送信時には、
Laravel がトークンを検証する。

トークンが存在しない場合や、
値が一致しない場合は、
リクエストが拒否される。

Laravel では、
通常のフォームであれば
@csrf
を記述するだけで CSRF 対策を行える。

SQL インジェクションとは

SQL インジェクションは、
ユーザーがフォームなどから送信した文字列が、
SQL の一部として解釈されることで、
サイトが意図していない SQL が実行されてしまう攻撃。

本来、
入力フォームへ入力された文字列は、
単なるデータとして扱われるべきもの。

しかし、
入力値を適切に処理せずに SQL を組み立てると、
ユーザーが入力した文字列によって SQL の意味が変わってしまう場合がある。

その結果、
本来閲覧できないデータを取得されたり、
データを改ざん・削除されたりする危険がある。

攻撃例

例えば、
ユーザーを検索する下記の SQL があるとする。

SELECT * FROM users
WHERE name = '$name';

$name にフォームから送信されたユーザー名が入り、
ユーザー情報を検索する仕組み。

このフォームで、
以下の文字列を送信したとする。

' OR 1=1 --

この文字列がデータではなく SQL の一部として解釈されると、
SQL は以下のようになる。

SELECT * FROM users
WHERE name = '' OR 1=1 --';

これにより、
WHERE 条件が常に真となるため、
users テーブルの全てのデータが取得されてしまう。

一般的な対策

SQL インジェクションを防ぐためには、
入力値を文字列として安全に扱う必要がある。

一般的には、
プレースホルダを使用した
プリペアドステートメントが利用される。

プレースホルダ
後から値を埋め込むための目印。
プリペアドステートメント
SQL とデータを分離して実行する仕組み。

プレースホルダを使用すると、
ユーザーが入力した値は SQL の一部ではなく、
単なるデータとして扱われる。

PHP の例

$stmt = $pdo->prepare(
    "SELECT * FROM users WHERE name = ?"
);

$stmt->execute([$name]);

この例では、
?
がプレースホルダ。

実際の値は execute() で後から渡されるため、
ユーザーが入力した値によって
SQL の意味が書き換えられることを防げる。

Laravel の対策

Laravel では、
Eloquent ORM や Query Builder を使用することで、
基本的にプレースホルダが自動で利用される。

例えば、
以下のコード。

$user = User::where('name', $name)->first();

Laravel が内部で安全な SQL を生成するため、
SQL インジェクションのリスクを大幅に減らせる。

そのため、
Laravel では入力値を直接 SQL へ連結するのではなく、
Eloquent や Query Builder を利用することが推奨される。

ただし、
生 SQL を自分で組み立てる場合は、
Laravel を使用していても SQL インジェクションの危険があるため注意が必要。

パスワードはどのように保存するべきか

パスワードは、
そのままの文字列で保存してはいけない。

例えば、
ユーザーが入力したパスワードを
そのまま DB に保存してしまうと、
DB の情報が漏洩した際に、
パスワードもそのまま流出してしまう。

このような保存方法を
「平文保存」
と呼ぶ。

パスワードを平文保存すると、
同じパスワードを使い回している他サービスへの
不正ログイン被害にもつながる可能性がある。

一般的な保存方法

パスワードは、
ハッシュ化して保存するのが基本。

ハッシュ化とは、
入力された文字列を
元に戻せない別の文字列へ変換する処理。

例えば、
password123
というパスワードをそのまま保存するのではなく、
ハッシュ化された文字列を DB に保存する。

password123

↓ ハッシュ化

$2y$12$5fHf0h9zQq3a8f5sE7v9eO...

ログイン時は、
入力されたパスワードを再度ハッシュ化して比較するのではなく、
専用の検証処理を使って、
入力値と保存済みハッシュが一致するか確認する。

ハッシュ化は暗号化とは異なり、
基本的に元の文字列へ戻すことはできない。

PHP での例

PHP では、
password_hash()
を使用してパスワードをハッシュ化できる。

<?php

$password = 'password123';

$hash = password_hash($password, PASSWORD_DEFAULT);

password_hash()
を使用すると、
安全なアルゴリズムを使って
パスワードをハッシュ化できる。

ログイン時は、
password_verify()
を使用して、
入力されたパスワードと保存済みのハッシュを比較する。

<?php

$password = 'password123';
$hash = '$2y$12$5fHf0h9zQq3a8f5sE7v9eO...';

if (password_verify($password, $hash)) {
    echo 'ログイン成功';
}

Laravel での対策

Laravel では、
Hash
ファサードを使用して
パスワードをハッシュ化できる。

use Illuminate\Support\Facades\Hash;

$hashedPassword = Hash::make($request->password);

Hash::make()
を使用すると、
パスワードを安全な形式でハッシュ化できる。

ログイン時の確認には、
Hash::check()
を使用できる。

if (Hash::check($request->password, $user->password)) {
    // パスワードが一致した場合の処理
}

Laravel の認証機能を使用する場合、
パスワードの検証処理は
Laravel 側で用意された仕組みによって行われる。

パスワードは絶対に平文で保存せず、
Laravel では
Hash::make()
などを使用してハッシュ化して保存する。

認証と認可の違い

Web アプリのセキュリティでは、
「認証」と「認可」という言葉がよく登場する。

名前が似ているため混同されやすいが、
意味は異なる。

認証(Authentication)

認証とは、
「そのユーザーが誰なのかを確認すること」。

例えば、
ログイン画面でメールアドレスとパスワードを入力し、
本人であることを確認する処理が認証。

ログイン成功後は、
システムが
「この人は user@example.com である」
と識別できるようになる。

認証は、
「あなたは誰ですか?」
を確認する仕組みと考えると分かりやすい。

認可(Authorization)

認可とは、
「そのユーザーに何を許可するかを決めること」。

例えば、

のように、
ユーザーごとに実行できる操作を制御する。

認可は、
「あなたは何をしてよいですか?」
を判断する仕組み。

認証と認可の関係

一般的には、
まず認証を行い、
その後に認可を行う。

例えば、

  1. ログインする(認証)
  2. 管理画面へアクセスする(認可)

という流れになる。

ログインしていないユーザーは、
そもそも認証されていないため、
管理画面へアクセスできない。

また、
ログイン済みでも一般ユーザーの場合は、
管理者専用機能を利用できない。

Laravel での例

Laravel では、
認証機能として
Laravel Breeze や Laravel Jetstream などが利用されることが多い。

また、
Middleware や Gate、
Policy などを使用して認可を実装できる。

Route::middleware('auth')->group(function () {

    Route::get('/mypage', function () {
        //
    });

});

この例では、
ログイン済みユーザーのみが
マイページへアクセスできる。

これは認証を利用したアクセス制御の例。

さらに管理者のみアクセス可能にする場合は、
認可の仕組みを利用して権限チェックを行う。

認証は「誰なのかを確認すること」、
認可は「何を許可するかを決めること」。
この違いは Laravel 学習初期に必ず理解しておきたいポイント。

セキュリティを高めるための開発ルール

Laravel には、
セキュリティ対策のための機能が多数用意されている。

ただし、
Laravel を使用しているだけで
自動的に安全なアプリになるわけではない。

セキュリティを高めるためには、
Laravel の機能を正しく使いながら、
危険な実装を避けることが重要。

ユーザー入力を信用しない

フォームや URL パラメータなど、
ユーザーから送信される値は、
常に不正な値が含まれる可能性がある。

そのため、
入力値は必ず Validation を行い、
想定した形式のデータか確認する。

Blade の自動エスケープを無効化しない

Blade の
{{ }}
は、
出力内容を自動でエスケープする。

一方で、
{!! !!}
は HTML をそのまま出力するため、
ユーザー入力に対して安易に使用しない。

生 SQL を多用しない

SQL を文字列として直接組み立てると、
SQL インジェクションの原因になる可能性がある。

Laravel では、
Eloquent ORM や Query Builder を使用し、
入力値を安全に扱うことが基本。

パスワードを平文保存しない

パスワードは、
そのまま DB に保存してはいけない。

Laravel では、
Hash::make()
を使用してハッシュ化した値を保存する。

認証と認可を分けて考える

ログイン済みかどうかを確認するだけでは、
十分なアクセス制御とはいえない。

ログインしているユーザーに対しても、
どの操作を許可するのかを確認する必要がある。

Laravel の標準機能を正しく利用する

Laravel には、
CSRF 対策、Validation、認証、認可、
パスワードハッシュ化などの機能が用意されている。

独自実装で無理に対応するのではなく、
まずは Laravel の標準機能を正しく利用することが重要。

まとめ

Laravel には、
セキュリティ対策のための機能が多数用意されている。

そのため、
Laravel の標準機能を正しく利用するだけでも、
多くの攻撃リスクを軽減できる。

例えば、
以下のような対策が Laravel に標準搭載されている。

攻撃 Laravel の対策
XSS Blade の {{ }} による自動エスケープ
CSRF @csrf による CSRF トークン検証
SQL インジェクション Eloquent ORM・Query Builder のプレースホルダ利用
パスワード漏洩 Hash::make() によるハッシュ化
不正アクセス 認証機能・Middleware・Gate・Policy

ただし、
Laravel を使用しているからといって、
全ての攻撃を自動で防げるわけではない。

例えば、
生 SQL を直接組み立てたり、
Blade の自動エスケープを無効化したりすると、
脆弱性を作り込んでしまう可能性がある。

Laravel の標準機能を理解し、
正しく利用することが重要。