セキュリティ4 択難易度 応用

状況

商品名の部分一致検索(Python の sqlite3)のレビュー。word は検索欄の入力で、SQL インジェクションになると指摘したところ、直し方の案が 4 つ出た。

直し方として正しいものは?

def search_items(conn, word):    sql = f"SELECT * FROM items WHERE name LIKE '%{word}%'"    return conn.execute(sql).fetchall()

正答

  1. conn.execute("SELECT * FROM items WHERE name LIKE '%?%'", (word,))
  2. conn.execute("SELECT * FROM items WHERE name LIKE '%" + word + "%'")
  3. conn.execute("SELECT * FROM items WHERE name LIKE ?", (f"%{word}%",))
  4. conn.execute("SELECT * FROM items WHERE name LIKE '%' + ? + '%'", (word,))

解説

LIKE の部分一致でも、入力は ? で値として渡し、% は値の側に付ける。'%?%' のように引用符の中に書いた ? はただの文字でプレースホルダにならず、sqlite3 は「バインドする数が合わない」とエラーにする。+ で連結すると入力が SQL 文の一部になり、' を含む入力で条件を書き換えられる。SQLite の + は数値の足し算なので、'%' + ? + '%' は 0 になり、名前が 0 の行しか見つからない(文字列の連結は ||)。'%' || ? || '%' と書くのも正しい直し方。入力に含まれる % や _ はワイルドカードとして働くので、必要なら ESCAPE で扱う。

参考: cheatsheetseries.owasp.org

sql-injectionplaceholderlikepython

この問題を含む セキュリティ のテストを制限時間つきで解く

セキュリティクイズへ