LoginSignup
gymfk
@gymfk

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

検索ワードの配列を使って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 の例ですが、以下の記事を見てください。

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

1Like

Comments

  1. @gymfk

    Questioner

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

$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); 
1Like

Comments

  1. @gymfk

    Questioner

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

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

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

  2. @gymfk

    Questioner

    【追記】

    ありがとうございます、上手くいきました!
    『 ':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>";
    }
    

Your answer might help someone💌