LoginSignup
@gymfk

検索ワードの配列を使ってPHP+SQLのSELECT文を作ったがSQLインジェクション対策に失敗

解決したいこと

検索ワードの配列を使ってPHP+SQLのSELECT文をつくり、結果は正しく表示されますが SQLインジェクション対策に対応できていません、アドバイスがありましたらお願いいたします

$Keyword = 'ワード1 ワード2 ワード3';
$KeywordList = mb_split("[  ]", $Keyword);
$countKeyword = count($KeywordList);

for ($i = 0; $i < $countKeyword; $i++) {
    if ($i == 0) {
        $searchword = "((concat(yoyaku_name,yoyaku_tel,yoyaku_comment) like '%".$KeywordList[$i]."%')";
    } else {
        $searchword .= " AND (concat(yoyaku_name,yoyaku_tel,yoyaku_comment) like '%".$KeywordList[$i]."%')"
    }
}
$searchword .= ")";

try {
$db = new PDO('mysql:dbname='.xxxxx.'; host='.xxxxx.'; charset=utf8', xxxxx, xxxxx);
} catch(PDOException $e) {
   echo '接続エラー:' . $e->getMessage();
}
$db->query('SET NAMES utf8');
$stmt = $db->prepare("SELECT * FROM テーブル名 WHERE $searchword order by yoyaku_date desc");

//  ↓ これを使ってチャレンジしたが失敗
// $stmt = $db->prepare("SELECT * FROM テーブル名 WHERE :searchword order by yoyaku_date desc"); 
// $stmt->bindParam(':searchword', $searchword, PDO::PARAM_STR); 


$stmt->execute();
foreach ($stmt as $row) {
	$row['yoyaku_name']." - ".$row['yoyaku_tel'].." - ".$row['yoyaku_comment']."<br>";
}

チャレンジしたいこと

SELECT文内に変数を使うのはマズいと思い、下記を使って頑張りましたがエラーで出ずに結果が空白でした

$stmt = $db->prepare("SELECT * FROM テーブル名 WHERE :searchword order by yoyaku_date desc"); 
$stmt->bindParam(':searchword', $searchword, PDO::PARAM_STR);
0

2Answer

SQLインジェクション対策に対応できていません

何故そう思うのですか? SQL 文をユーザーが入力した文字列を使って組み立てているからですか?

であれば、SQL 文をパラメータ化してはいかがですか?

何故パラメータ化が SQL インジェクション防止に役立つかは、ADO.NET + SQL Server の例ですが、以下の記事を見てください。

上の記事からもリンクが貼ってありますが、一般的な話として以下の記事も参考になると思います。

1

コメントありがとうございます
私の理解不足でした、リンク先を読んで勉強させて頂きます

$stmt = $db->prepare("SELECT * FROM テーブル名 WHERE :searchword order by yoyaku_date desc"); 
$stmt->bindParam(':searchword', $searchword, PDO::PARAM_STR);

これがうまく動かないのは変数$searchwordが部分的なSQLだからだと思います。
SQLインジェクションはパラメータに部分的なSQLを仕込んで想定外の動作をさせる攻撃なので、その対策をした結果として、searchwordパラメータの部分的なSQLが機能していない状態だと想像します。

解決方法は、パラメータの部分のみ動的にバインドします。

- $searchword .= " AND (concat(yoyaku_name,yoyaku_tel,yoyaku_comment) like '%".$KeywordList[$i]."%')"
+ $searchword .= " AND (concat(yoyaku_name,yoyaku_tel,yoyaku_comment) like '%:keyword".$i."%')"
$stmt->bindParam(':keyword'.$i, $KeywordList[$i], PDO::PARAM_STR); 
1

コメントありがとうございます

アドバイス頂いた内容でとても勉強になりました

月曜に出社したら試して再度コメントを書きますね

【追記】

ありがとうございます、上手くいきました!
『 ':keyword'.$i 』という発想がなく、とても勉強になりました

$Keyword = 'ワード1 ワード2 ワード3'; // ワード数は可変
$KeywordList = mb_split("[  ]", $Keyword);
$countKeyword = count($KeywordList);

for ($i = 0; $i < $countKeyword; $i++) {
    if ($i == 0) {
        $searchword  .= "((concat(yoyaku_name,yoyaku_tel,yoyaku_comment) like :keyword".$i.")";
    } else {
        $searchword  .= " AND (concat(yoyaku_name,yoyaku_tel,yoyaku_comment) like :keyword".$i.")";
    }
}
$searchword .= ')';

try {
$db = new PDO('mysql:dbname='.xxxxx.'; host='.xxxxx.'; charset=utf8', xxxxx, xxxxx);
} catch(PDOException $e) {
   echo '接続エラー:' . $e->getMessage();
}
$db->query('SET NAMES utf8');
$stmt = $db->prepare("SELECT * FROM テーブル名 WHERE $searchword order by yoyaku_date desc");

for ($i = 0; $i < $countKeyword; $i++) {
	$KeywordList[$i] = '%'.$KeywordList[$i].'%';
	$stmt->bindParam(':keyword'.$i, $KeywordList[$i], PDO::PARAM_STR);
}

$stmt->execute();
foreach ($stmt as $row) {
	$row['yoyaku_name']." - ".$row['yoyaku_tel']." - ".$row['yoyaku_comment']."<br>";
}

Sign up for free and join this conversation.

Sign Up
If you already have a Qiita account Login