PHP / SQLデータベースクエリの優れた実践とセキュリティ
-
05-07-2019 - |
質問
だから、私はややベテランのphp開発者であり、2007年以来「気の毒」になっています。ただし、アプリケーションを保護することになると、私はまだ比較的無頓着です。自分ができることやすべきことをすべて知っているわけではありません。
PHP Webアプリケーションの保護を取り上げて、読み進めています途中で物事をテストします。データベースのクエリに関連する一般的なSOグループに対していくつか質問があります(主にmysqlの下):
データベースにデータを置くアプリを作成するとき、mysql_real_escape_stringと入力データの一般的なチェック(is_numericなど)で十分ですか? SQLインジェクションとは異なる他のタイプの攻撃についてはどうですか。
誰かがストアドプロシージャと準備されたステートメントを説明するよりも少し多くの情報を説明してもらえますか-あなたはそれらを作成し、それらを呼び出します。それらがどのように機能し、どのような検証が舞台裏で行われるのかを知りたい。
私はphp4にバインドされた環境で作業していますが、当面はphp5はオプションではありません。他の誰かが以前にこのポジションにいたことはありますか?すべてのクールな子供たちがその甘い新しいmysqliインターフェイスを使用している間にアプリケーションを保護するために何をしましたか?
人々が有利であることがわかっている一般的なグッドプラクティスは何ですか?アップグレードと可能な移行(php4からphp5への移動など)に耐えることができるインフラストラクチャを作成することに重点を置いています。
注:php-mysqlセキュリティにヒットするこれに類似するものを見つけることができませんでした。
解決
私の推奨事項:
- mysqliを捨ててPDO (mysqlドライバーを使用) )
- PDOパラメーター化された準備済みステートメントの使用
次のようなことができます:
$pdo_obj = new PDO( 'mysql:server=localhost; dbname=mydatabase',
$dbusername, $dbpassword );
$sql = 'SELECT column FROM table WHERE condition=:condition';
$params = array( ':condition' => 1 );
$statement = $pdo_obj->prepare( $sql,
array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
$statement->execute( $params );
$result = $statement->fetchAll( PDO::FETCH_ASSOC );
長所:
- PDOがすべてを自動で行うため、手動でエスケープする必要はありません。
- 突然、データベースバックエンドを切り替えるのは比較的簡単です。
CON:
- 私は何も考えられません。
他のヒント
owaspリンクのあるJavierの回答は良い出発点です。
さらにできることがいくつかあります:
-
SQLインジェクション攻撃については、"などの一般的なSQLステートメントを入力から削除する関数を作成できます。ドロップ"または" DELETE * WHERE"のように:
* $ sqlarray = array(" DROP"、 `` or 1 = 1 '' ,, `` union select '' ,, `` SELECT * FROM '' ,, `` select host '' ,, `` create table ''、 ``; FROMユーザー"、"ユーザーWHERE"); *
次に、この配列に対して入力をチェックする関数を作成します。 $ sqlarray内の内容がユーザーからの一般的な入力にならないようにしてください。 (これにstrtolowerを使用することを忘れないでください、louに感謝します。)
-
memcacheがPHP 4で動作するかどうかはわかりませんが、memcacheを使用して特定のリモートIPアクセスを許可することで、memcacheでスパム保護を設定できます。 。
-
特権は重要です。挿入特権(注文処理など)のみが必要な場合は、挿入特権と選択特権のみを持つユーザーを使用して、注文プロセスページでデータベースにログインする必要があります。これは、SQLインジェクションが成功した場合でも、INSERT / SELECTクエリのみを実行でき、削除または再構築はできないことを意味します。
-
重要なPHP処理ファイルを/ includeなどのディレクトリに配置します。次に、その/ includeディレクトリへのすべてのIPアクセスを禁止します。
-
ソルトされたMD5をユーザーのエージェント+ remoteip +ソルトでユーザーのセッションに挿入し、ページの読み込みごとに正しいMD5がCookieにあることを確認させます。
-
特定のヘッダーを許可しない( http://www.owasp.org/index.php / Testing_for_HTTP_Methods_and_XST )。 PUT(ファイルのアップロードが必要ない場合)/ TRACE / CONNECT / DELETEヘッダーを許可しません。
私は通常PHPを使用していないため、要件に特化したアドバイスを提供することはできませんが、OWASPページ、特にトップ10の脆弱性レポートをご覧になることをお勧めします。 http://www.owasp.org/index.php/Top_10_2007
このページでは、各脆弱性について、異なるプラットフォーム(.Net、Java、PHPなど)で問題を回避するためにできることのリストを取得します
準備されたステートメントについては、特定のクエリ中にパラメータの数とタイプをデータベースエンジンに通知することで機能します。この情報を使用して、エンジンはどの文字が実際のパラメータの一部であり、文字列区切り文字としての 'ではなく、データの一部として'(アポストロフィ)のようなSQLとして解析されます。申し訳ありませんが、PHPを対象とした詳細情報は提供できませんが、これが役立つことを願っています。
AFP、PHP / mySQLには通常、パラメーター化されたクエリはありません。
mysql_real_escape_string()
で sprintf()
を使用すると、うまく機能するはずです。 sprintf()
に適切なフォーマット文字列(たとえば、整数の"%d")を使用する場合、かなり安全です。
間違っているかもしれませんが、 mysql_real_escape_string
ユーザー提供のデータについて?
それらが数字の場合を除き、その場合、たとえば ctype_digit
または is_numeric
または sprintf
(%d
または%u
数値への入力を強制します)。
また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<?php if (isset(
間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['product_name']) && isset(例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['product_description']) && isset(例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['user_id'])) { // Connect $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password'); if(!is_resource($link)) { echo "Failed to connect to the server\n"; // ... log the error properly } else { // Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON. if(get_magic_quotes_gpc()) { $product_name = stripslashes(例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['product_name']); $product_description = stripslashes(例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['product_description']); } else { $product_name =例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['product_name']; $product_description =例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['product_description']; } // Make a safe query $query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)", mysql_real_escape_string($product_name, $link), mysql_real_escape_string($product_description, $link),例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>間違っているかもしれませんが、
mysql_real_escape_string
ユーザー提供のデータについて?それらが数字の場合を除き、その場合、たとえば
ctype_digit
またはis_numeric
またはsprintf
(%d
または%u
数値への入力を強制します)。また、SELECT、INSERT、UPDATE、およびDELETEのみが可能なphpスクリプト用のmysqlユーザーを用意することは、おそらく良い考えです...
php.netの例
POST['user_id']); mysql_query($query, $link); if (mysql_affected_rows($link) > 0) { echo "Product inserted\n"; } } } else { echo "Fill the form properly\n"; }例#3「ベストプラクティス」クエリ
各変数でmysql_real_escape_string()を使用すると、SQLインジェクションが防止されます。この例は、「ベストプラクティス」を示しています。 Magic Quotes設定とは関係なく、データベースを照会する方法。
クエリは正しく実行されるようになり、SQLインジェクション攻撃は機能しなくなりました。
<*>
DBへの書き込みを伴うアクティビティにはストアドプロシージャを使用し、すべての選択にはバインドパラメータを使用します。