Spam protection, AntiSpam, FireWall by CleanTalk のSQLインジェクション脆弱性(修正済み)

WordPress に設置するフォームやコメントフォームなどに対するスパムをブロックするプラグイン、Spam protection, AntiSpam, FireWall by CleanTalk に脆弱性が見つかりました。

バージョン 5.153.4 にて修正済みです。
それ以前のバージョンをお使いの方は、アップデートしてください。

このプラグインは広義ではサイトをセキュアに保とうという機能を提供していますが、かえって脆弱性を紛れ込ませることになったために、少し興味を持ちました。

詳細な情報は以下のサイトに記載されています。

Wordfence – SQL Injection Vulnerability Patched in CleanTalk AntiSpam Plugin

SQLインジェクション脆弱性

このプラグインでは、ユーザーエージェントをデータベースの独自テーブルに保存します。
WordPress が標準で用意しているオプションやメタデータのテーブルへの保存は、WordPress が標準でデータを操作する関数を用意しています。

しかし、独自テーブルへの操作は自身で SQL を準備するなどする必要があります。
その SQL の処理がまずく、ユーザーエージェントにプラグインデベロッパーが意図しない SQL 文をまぎれこませ、それを実行させることができる、SQL インジェクション脆弱性が生まれてしまいました。

このプラグインの脆弱性を利用することは比較的簡単で、それによって

  • データベースを削除する。
  • 投稿した覚えのない記事を挿入する。
  • 記事を書き換える。

などの操作が可能な状態でした。

SQLインジェクション脆弱性を生まないために

このような、値をテーブルに挿入・更新する際にSQL インジェクション脆弱性が生じないようにするためのプログラムの書き方は、一般によく知られていて定番化しています。
どのようなプログラミング言語であれ、Prepared Statement が用意されている場合にはそれを正しく使って SQL文 に値をセットすることです。

php では PDO::preparehttps://www.php.net/manual/ja/pdo.prepare.phpmysqli::prepare が用意されていますので、それらを使います。

WordPress では独自に wpdb::prepare が用意されています。
(WordPress がなぜ mysqli の prepare を使っていないのかは私には分かりません)

ただ、単に Prepared Statement を使えば良いというわけでもありません。
上記リンクをどちらでも見ていただければお分かりと思いますが、それぞれの関数に渡す第一引数は SQL 文の値をセットする箇所を ? などに置き換えているものです。

つまり、この第一引数に SQL 文そのものを書いてしまうこともできます。
それでは、セットする値をサニタイズできずにやはり SQL インジェクション脆弱性が生じてしまいます。

独自に SQL を組む際は Prepared Statement を正しくお使いください。