English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

MySQL 及び SQL インジェクション

如果您通过网页获取用户输入的数据并将其插入一个MySQL数据库,那么就有可能发生SQL注入安全的问题。

本章节将为大家介绍如何防止SQL注入,并通过脚本来过滤SQL中注入的字符。

所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

我们永远不要信任用户的输入,我们必须认定用户输入的数据都是不安全的,我们都需要对用户输入的数据进行过滤处理。

以下示例中,输入的用户名必须为字母、数字及下划线的组合,且用户名长度为 8 到 20 个字符之间:

if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches))
{
   $result = mysqli_query($conn, "SELECT * FROM users 
                          WHERE username=$matches[0]");
}
 else 
{
   echo "username 输入异常";
}

特殊文字をフィルタリングしない場合のSQLの状況を見てみましょう:

// $nameに不要なSQL文が挿入されていることを設定
$name = "Qadir'; DELETE FROM users;";
 mysqli_query($conn, "SELECT * FROM users WHERE name='{$name}'");

上記のインジェクション文では、$nameの変数にフィルタリングが行われていません。$nameには必要でないSQL文が挿入されており、usersテーブルのすべてのデータが削除されます。

PHPのmysqli_query()では複数のSQL文を実行することは許可されていませんが、SQLiteやPostgreSQLでは複数のSQL文を実行することができます。したがって、これらのユーザーのデータに対して厳格な検証を行う必要があります。

SQLインジェクションを防ぐために、以下のポイントに注意する必要があります:

  • 1.ユーザーの入力を絶対に信頼しないでください。ユーザーの入力を検証し、正規表現や長さの制限を使用して、シングルクォートや 双-"を使用して変換などを行います。

  • 2.動的SQLを構築することは絶対に避けるべきであり、パラメータ化SQLやストレージプロシージャを使用してデータのクエリや存取を行うべきです。

  • 3.管理権限のデータベース接続を使用することは絶対に避けるべきであり、各アプリケーションに権限が制限されたデータベース接続を使用するべきです。

  • 4.機密情報を直接保存しないでください。パスワードやその他の敏感情報を暗号化またはハッシュ化してください。

  • 5.アプリケーションの異常情報は、可能な限り少ないヒントを提供すべきであり、カスタムエラーメッセージを使用して元のエラーメッセージを包装するのが最善です。

  • 6.sqlインジェクションの検出方法は、一般的にサブスクライプソフトウェアやウェブプラットフォームを使用して検出されます。ソフトウェアでは、jskyなどのSQLインジェクション検出ツールを使用し、ウェブプラットフォームでは、亿思ウェブセキュリティプラットフォームの検出ツールやMDCSOFT SCANなどを使用します。MDCSOFT-IPSは効果的にSQLインジェクション、XSS攻撃などを防ぐことができます。

SQLインジェクションを防ぐ

スクリプト言語、例えばPerlやPHPでは、ユーザー入力データをエスケープすることでSQLインジェクションを防ぐことができます。

PHPのMySQLエクステンションはmysqli_real_escape_string()関数を提供し、特殊な入力文字をエスケープします。

if (get_magic_quotes_gpc()) 
{
  $name = stripslashes($name);
}
$name = mysqli_real_escape_string($conn, $name);
 mysqli_query($conn, "SELECT * FROM users WHERE name='{$name}'");

Like文における注入

likeクエリ時に、ユーザーが入力した値に"_"と"%"がある場合、このような状況が発生します:ユーザーは本来"abcd_"をクエリしたいと思っていましたが、クエリ結果には"abcd_"、"abcde"、"abcdf"などが含まれています;ユーザーは""をクエリしたいと思っています。30%"(注:3割)の場合でも問題が発生します。

PHP スクリプトでは、addcslashes() 関数を使用して以下のような処理を行うことができます。以下に例を示します:

$sub = addcslashes(mysqli_real_escape_string($conn, "%something_"), "%_");
// $sub == \%something\_
 mysqli_query($conn, "SELECT * FROM messages WHERE subject LIKE '{$sub}%';

addcslashes() 関数は指定された文字の前にアンカーサラを追加します。

構文形式:

addcslashes(string,characters)
パラメータ説明
文字列必須。チェックする文字列を指定します。
文字オプション。addcslashes() に影響を与える文字または文字範囲を指定します。

具体的なアプリケーションについては、以下を参照してください:PHP addcslashes() 関数