0

初心者として、私は通常の MySQL php 関数の使用を勧める PHP MySQL チュートリアルに従いました。ただし、PDO の方が優れていると言われたので、コードを PDO に変換しています。次の問題に遭遇しました:

    $query = $uspdb->prepare("SELECT post_id, is_approved, reports FROM ? WHERE id=? AND ?");
    $query->bindValue(1, $table, PDO::PARAM_INT);
    $query->bindValue(2, $id, PDO::PARAM_INT);
    $query->bindValue(3, checkPermission("comment_moderation"),PDO::PARAM_BOOL);
    $query->execute;
    $result = $query->fetch(PDO::FETCH_ASSOC);

最初の行は、次の PDO 例外をスローします。

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? WHERE id=? AND ?' at line 1

何故ですか?構文の何が問題なのかわかりません。私が読んでいるチュートリアルでは、「.$id.」ではなく bindValue または execute(array(stuff)) を使用してパラメーターを追加する必要があると書かれています。など、より安全なので、これは何らかの理由で機能しません。

4

2 に答える 2

1

残念ながら、準備されたステートメントはデータ リテラルのみを表すことができます。(エミュレートされた準備の場合)。そのため、開発者は自分で識別子を処理する必要があります。PDO はこの問題について何の助けも提供しません

動的識別子を安全にするには、次の 2 つの厳密な規則に従う必要があります。

  1. 識別子を適切にフォーマットするため。意味
    • 識別子をバッククォートで囲みます。
    • バッククォートを 2 倍にしてエスケープします。
  2. ハードコードされたホワイトリストと照合して検証します。

フォーマット後、$table 変数をクエリに安全に挿入できます。したがって、コードは次のようになります。

$field = "`".str_replace("`","``",$field)."`";
$sql   = "SELECT * FROM t ORDER BY $field";

ただし、ORDER BY のようなケースではこのようなフォーマットで十分ですが、他のほとんどのケースでは、別の種類のインジェクションの可能性があります。ユーザーが表示できるテーブルまたはフィールドを選択できるようにすることで、パスワードやその他の個人データなどの機密情報。したがって、許可された値のリストに対して動的識別子を確認することをお勧めします。以下に簡単な例を示します。

$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed));
if ($key === false) {
    throw new Exception('Wrong field name');
}
$field = $allowed[$key];
$query   = "SELECT $field FROM t"; //value is safe
于 2013-08-05T07:16:18.270 に答える
0

いつものように、私は質問をしてから数秒で問題を解決します。

問題は、テーブル名や列名ではなく、このようなキー値のみをバインドできることです。以前と同じように、テーブルと列の名前を手動で挿入し続ける必要があります。

$query = $uspdb->prepare("SELECT post_id, is_approved, reports FROM $table WHERE id=? AND ?");
$query->execute(array($id,checkPermission("comment_moderation")));
$result = $query->fetch(PDO::FETCH_ASSOC);

テーブルまたは列の名前がユーザーの裁量に任されている場合は、追加の手順を実行してサニタイズする必要があります。これについては、上記のあなたの常識の回答で詳しく説明しています。私の場合、それは次のコードでした:

$type = $_GET[type];

switch($type) {
    case "review":
        $table = "site_cmt_reviews";
        break;
    default:
        $table = "site_cmt_articles";
}

それでも、読んでくれてありがとう!

于 2013-08-05T07:17:58.460 に答える