PHPでのSQLインジェクションへの対策方法を現役エンジニアが解説【初心者向け】
初心者向けにPHPでのSQLインジェクションへの対策方法について現役エンジニアが解説しています。SQLインジェクションとは、Webサイトから入力された値を使用し悪意のあるSQL文を組み立てることです。SQLインジェクションへの対策としてPDOクラスを使ったプリペアードステートメントについて解説します。
テックアカデミーマガジンは受講者数No.1のプログラミングスクール「テックアカデミー」が運営。初心者向けにプロが解説した記事を公開中。現役エンジニアの方はこちらをご覧ください。 ※ アンケートモニター提供元:GMOリサーチ株式会社 調査期間:2021年8月12日~8月16日 調査対象:2020年8月以降にプログラミングスクールを受講した18~80歳の男女1,000名 調査手法:インターネット調査
PHPでのSQLインジェクションへの対策方法について、TechAcademyのメンター(現役エンジニア)が実際のコードを使用して初心者向けに解説します。
そもそもPHPについてよく分からないという方は、PHPとは何なのか解説した記事を読むとさらに理解が深まります。
なお本記事は、TechAcademyのオンラインブートキャンプPHP/Laravel講座の内容をもとに紹介しています。
今回は、PHPに関する内容だね!
どういう内容でしょうか?
PHPでのSQLインジェクションへの対策方法について詳しく説明していくね!
お願いします!
この記事ではPHPでのSQLインジェクションへの対策方法について解説します。
目次
SQLインジェクションとは
SQLインジェクションとは、アプリケーションのセキュリティ的な不備をついてWebサイトなどから入力された値を使用して悪意のあるSQL文を組み立てることです。
SQLインジェクション対策をしていないアプリケーションは、入力された値を元に実装者が意図しないSQLを生成されることがあります。その結果、データベースを不正に操作されることによりパスワードなどの重要なデータが読み取られたり、データの削除や編集が行われ流ことにより、ときには甚大な被害を招くことがあります。
例えばSQL文を入力値を使って作成する時に以下のように作成した場合です。
$sql ="SELECT * FROM users WHERE name ='" . $name . "'";
一見普通の処理のように見えますが例えば$nameに以下のような値が渡ってきた場合どのようになるのでしょうか。
$name = "' or 'a' = 'a";
と入力された場合、実行されるSQL文は以下のようになります。
SELECT * FROM users WHERE name ='' or 'a' = 'a';
これはnameが空の文字になるデータかつ’a’が’a’となるデータを取得することになります。’a’が’a’に成り立つことは当たり前なので全てのデータで成り立つことになります。
つまり、本来であればnameカラムが入力された$nameと等しいデータのみ取得するはずが、全てのデータを取得するSQL文へと変わってしまうということです。
[PR] PHPを学んで未経験からWebエンジニアを目指す方法とは
SQLインジェクションへの対策方法
PHPでのSQLインジェクションへの対策としてよく使われるのがプリペアードステートメントを使うという方法です。
プリペアードステートメントは、SQL文で検索に必要な値や、登録や更新時の値を埋め込みでSQL文に入れるようにする方法のことです。
先ほどのSQL文ではSQL文と検索に必要な値を「.」で連結させていましたが、プリペアードステートメントを使うと以下のように記述します。
$sql ="SELECT * FROM users WHERE name =?";
?の部分に後から値を埋め込みます。先ほど問題があった「’ or ‘a’ = ‘a」のような値であってもそれを一つの文字列として認識するようになります。つまり、実際に実行されるのSQLは以下のようになります。
SELECT * FROM users WHERE name =''' or ''a'' = ''a''';
つまりnameカラムに入っている値が「’ or ‘a’ = ‘a」と一致するデータという意味になることによりSQLインジェクション対策となります。
実際に書いてみよう
では実際にSQLインジェクションへの対策をしたソースを書いてみましょう。
ソースコード
<?php try { $records = []; $name = "test01"; $pdo = new PDO( 'mysql:host=localhost;dbname=dbname;charset=utf8', 'username, 'password' ); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $prepare = $pdo->prepare("SELECT * FROM person WHERE name = ?"); $prepare->bindParam(1, $name, PDO::PARAM_STR); $prepare->execute(); $records = $prepare->fetchAll(PDO::FETCH_ASSOC); var_dump($records); } catch(PDOException $e) { echo $e->getMessage(); }
実行結果
array(1) { [0]=> array(3) { ["id"]=> int(1) ["name"]=> string(6) "test01" ["age"]=> int(30) } }
PHPでデータベースを接続するためのクラスでPDOクラスがありますがオブジェクトを作成する際に「charset=utf8」として文字エンコーディングを指定しています。
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
をすることで静的プレースホルダを有効に設定し、SQL文の「?」のプリペアードステートメントに値をバインドする準備を行います。
SQL文の「?」に値を埋め込むためにbindParamメソッドを使います。
まとめ
この記事ではPHPでのSQLインジェクションへの対策方法について解説しました。
筆者プロフィール
メンターSさん
システムエンジニアとしてこれまで行政システムや医療用システムの保守、開発に携わりました。 JavaやPython、PHP、Kotlinなど様々な言語での開発経験があります。 |
内容分かりやすくて良かったです!
ゆかりちゃんも分からないことがあったら質問してね!
分かりました。ありがとうございます!
TechAcademyでは、初心者でもPHPやフレームワークのLaravelを使ってWebアプリケーション開発を習得できるオンラインブートキャンプPHP/Laravel講座を開催しています。
挫折しない学習方法を知れる説明動画や、現役エンジニアとのビデオ通話とチャットサポート、学習用カリキュラムを体験できる無料体験も実施しているので、ぜひ参加してみてください。