PHPでsqlインジェクション対策を行う方法を現役エンジニアが解説【初心者向け】

初心者向けにPHPでsqlインジェクション対策を行う方法について現役エンジニアが解説しています。sqlインジェクションとは外部からの入力値をそのまま使ってsql文を組み立てて実行してしまうことによる生じるセキュリティの問題です。PDOのプレースホルダーを利用して値をバイインドします。

TechAcademyマガジンはオンラインのプログラミングスクールTechAcademy [テックアカデミー]が運営する教育×テクノロジーのWebメディアです。初心者でもすぐ勉強できる記事が2,000以上あります。

今回は、PHPでsqlインジェクション対策を行う方法について、TechAcademyのメンター(現役エンジニア)が実際のコードを使用して初心者向けに解説します。

 

PHPについてそもそもよく分からないという方は、PHPとは何なのか解説した記事を読むとさらに理解が深まります。

 

なお本記事は、TechAcademyのオンラインブートキャンプ、PHP/Laravel講座の内容をもとに紹介しています。

 

田島悠介

今回は、PHPに関する内容だね!

大石ゆかり

どういう内容でしょうか?

田島悠介

PHPでsqlインジェクション対策を行う方法について詳しく説明していくね!

大石ゆかり

お願いします!

 

sqlインジェクションとは

sqlインジェクションとは、Webサイトなどから入力された値をそのまま使用して悪意のあるSQL文を組み立てることです。

データベース(DB)と連携して動作するWebサイトなどでは、外部から入力された値を元にSQL文を組み立てることがよくあります。

sqlインジェクションの脆弱性をもつWebサイトなどのアプリケーションは、入力された値を元に意図しないSQLを生成されることがあります。結果として、アカウントのパスワードなどの重要なDBのデータが読み取られたり、データの改ざんまたは削除が可能なため、時には甚大な被害を招くことになりかねません。

下記は、sqlインジェクションの一例です。

SELECT * FROM users WHERE username LIKE '%x'; SELECT password FROM users -- %'

セミコロンなどを入力値に含めることで、不正なSQL文を生成することが可能です。
 

sqlインジェクションを防ぐ方法

sqlインジェクションを防ぐためにPHPアプリケーションでは、以下の3つの対策を行う必要があります。

  1. 文字エンコーディングを指定する
  2. 静的プレースホルダを用いる
  3. バインド時に型を指定する

1.文字エンコーディングを指定することで、本来必要なバイト数未満のデータを送り,特殊文字を無効化するなどのsqlインジェクションを防ぐことができます。

2.SQL文をデータベースエンジン側にあらかじめ送信して、実行前に、SQL 文の構文解析などの準備をしておく方式です。あらかじSQL文をデータベースに送信しておくことで、文字列を組み立ててSQL文を生成し、不正なSQLの生成を防ぎます。

3.用意した静的プレースホルダ(SQL文)は、条件指定部分の値を当てはめられる形(プリペアードステートメント)にしておくことが多いです。そのため、値をプリペアードステートメントにバインドする時は、データ型を指定することで不正な値をバインドされることを防ぎます。
 

[PR] PHPのプログラミングで挫折しない学習方法を動画で公開中

実際に書いてみよう

それでは、実際に上記のポイントを抑えたPHPでの実装例を見てみましょう。

// 1. 文字エンコーディングを指定して DB に接続する
$dbh =
 new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8', 'username', 'password');
// 2-1. 静的プレースホルダを用いるようにエミュレーションを無効化
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "SELECT * FROM users WHERE email = ? AND password = ?";
// 2-2. プリペアドステートメントを準備
$sth = $dbh->prepare($sql);
// 3. 型を指定してパラメータにバインドする
$sth->bindParam(1, $email, PDO::PARAM_STR);
$sth->bindParam(2, $password, PDO::PARAM_STR);

1.では、「charset=utf8」として文字エンコーディングを指定しています。

2-1.では、静的プレースホルダを有効に設定し、2-2.で「?」のプリペアードステートメントに値をバインドする準備を行います。

3.では、bindParam()関数で値をバインドしています。

第一引数にはプリペアードステートメントの位置を、第二引数には、バインドする値を、第三引数には、PDO::PARAM_STRを使用し、データ型を文字列に指定しています。
 

筆者プロフィール

平野大輝(ひらのだいき)

スキル:PHP・Java・JavaScriptを用いて様々なアプリを開発するWebエンジニア。

 

大石ゆかり

内容分かりやすくて良かったです!

田島悠介

ゆかりちゃんも分からないことがあったら質問してね!

大石ゆかり

分かりました。ありがとうございます!

 

TechAcademyでは、初心者でも最短4週間で、PHPやフレームワークのLaravelを使ってWebアプリケーション開発を習得できる、オンラインブートキャンプを開催しています。

また、現役エンジニアから学べる無料体験も実施しているので、ぜひ参加してみてください。