PHPでのSQLインジェクション攻撃防止/コードサンプル
数年の侵入テストと開発チームとのシステムのセキュリティ保護のための作業の後、私は、最も人気のあるすべてのwebアプリケーション開発言語とフレームワークでSQLインジェクション攻撃を防止する方法の詳細な説明を与える完全なブログ記事がなかったことに気付きました。 したがって、SQLインジェクションを防ぐための最も完全なガイドにするために、一連の複数の投稿を書くことにしました。
このガイドはオープンな一連の投稿であり、これは最初の投稿です。 私が技術を追加したい場合は、以下にコメントしてください。 このガイドでは、次のテクノロジを分析します:
- PHP
- Laravel
- Symfony
- CodeIgniter
- CakePHP
- FuelPHP
- ゼンド
- JEE
- JDBC
- JPA
- ASP.NET
- ADO.NET
- NETドッパー
- NHibernate
この最初の投稿は、PHP言語とそのすべてのフレームワークに焦点を当てます。 他の記載されている技術に対処するために、より多くの記事が続きます。
SQLインジェクション攻撃が何であるかわからない人のために、私は彼らにこれを説明するために小さな紹介をしましょう。 Sqlインジェクション攻撃は、不正なユーザーが悪意のあるSQL要求を正当な要求に注入しようとすると発生します。 SQLインジェクション攻撃の影響は、アプリ環境に関連する複数の要素によって状況によって異なり、情報漏洩のような”単純な”ものから完全なサーバー 攻撃者がこの脆弱性を悪用する方法や、blackboxテストでそれを発見する方法については、この投稿の目的ではないため、詳しくは説明しません。 私たちが見るのは、ソースコードでそれを発見する方法とそれを修正する方法です。
純粋なPHPソースコードでSQLインジェクション攻撃を防ぐ方法は?
私たちは、任意のフレームワークなしで最も古く、人気のある開発技術PHPの一つで私たちの旅を始めましょう。 ここで最初に行うことは、脆弱なソースコード行が脆弱性を識別できるようにどのように見えるかを知ることです。
認証要求の例を次に示します:
$request = "SELECT * FROM users WHERE username=". $_POST ." AND password = ". $_POST;
$result = $mysqli->query($request);
ここで、リクエストをよく見ると、ユーザーパラメータ$_POSTと$_POSTがフィルタリングなしでSQLリクエストに直接挿入されていることがわかります。 そうすることで、このコード行はSQLインジェクションに対して脆弱になります。
この脆弱性を修正するには、sqlリクエストでデータを使用する前にデータをフィルタリングする必要があります。 これを行うには、準備された文を使用するのが最善の解決策です。 準備されたステートメントを使用してこの脆弱性を修正する方法の例を次に示します:
$conn = new mysqli($servername, $username, $password, $dbname);
$stmt = $conn->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param($username, $password);
$stmt->execute();
良い練習
あなたはbind_param()関数を使用しない可能性がありますここではこれを行う方法の例です :
$conn = new mysqli($servername, $username, $password, $dbname);
$stmt = $conn->prepare("SELECT * FROM users WHERE username=:username AND password=:password");
$stmt-> execute(array('username'=>$_POST,'password'=>$_POST));
ソースコードの分析の年後…私はこの脆弱性を修正しながら、多くの開発者が行う興味深いエラーを発見しました。 次の例を見てみましょう:
$stmt = $conn->prepare("SELECT * FROM users WHERE username=".$_POST." AND password=".$_POST);
この例を見ると、準備された文を使用していることがわかります。 ただし、パラメータはSQL要求に直接挿入されます。 これは開発者が行う非常に一般的な間違いであり、準備された文を使用してもコードをSQLインジェクションに対して脆弱にします。
準備された文の背後にある考え方は、SQL要求に挿入する前にパラメータをフィルタリングすることです…これを念頭に置いてください。
非常に重要な注意:
PHPは、SQL要求をフィルタリングし、SQLインジェクションを防ぐためのいくつかの他の関数を提供していますが、そのうちのいくつ たとえば、mysql_real_escape_string()関数は、SQLインジェクションを防止するための最も知られているPHP関数の1つです。 残念ながら、この機能は本当に効率的です。 この関数を使用すると、MySQLライブラリは次の文字に円記号を追加します: NULL、\x00、\n、\r、\、’、”、および\x1a。:
$id = mysql_real_escape_string("1 OR 1=1");
$request = "SELECT * FROM users WHERE id = $id";
赤い色では、悪いユーザーがあなたに送信するものです
mysql_real_escape_string()は、そのような攻撃からあなたを保護しません。
このため、この関数の代わりにprepared statementsを使用することを常にお勧めします。
LARAVELフレームワークでSQLインジェクション攻撃を防ぐ方法は?
純粋なPHPコードに対するSQLインジェクション攻撃を見たので、フレームワークベースのwebアプリケーションの脆弱性をどのように修正できるかを見てみま これについて話を始める前に、まずLaravelフレームワークについて少し説明しましょう。
LARAVELはPHPで書かれたオープンソースのwebフレームワークで、model-view-controllerの原則を尊重し、完全にオブジェクト指向プログラミングで開発されています。
例1
以下は、laravelの脆弱なSQLリクエストの例です :
$user = DB::select('select * from users where username='. $request->post('username').' AND password='. $request->post('password'));
laravelフレームワークは、開発者が悪意のあるインジェクションからSQLリクエストを保護するのに役立ついくつかの素晴らしい機能を提供しています。 残念ながら、私がそのようなアプリで発見したSQLインジェクションの脆弱性のほとんどは、Laravel関数の誤用に関連しています。
前の例を分析してみましょう。LARAVELのドキュメントによると、DB::select関数は二つのパラメータを受け取ることができます。 最初のものはSQL要求であり、2番目のものはパラメータです。 したがって、SQLインジェクションのパラメータをフィルタリングするには、次の例のように2番目のパラメータを使用して要求にパラメータを挿入する必 とパスワード=?’, );
例2
Laravelはデータベースと通信するための複数の方法を持っていますこの例では、laravelは、次の例のように、自動的にユーザーデータをフィルタリングするいくつかの関数を使用するように開発者に強制することがわかります:
Users::where('username', $request->get('username'))->orderBy($request->get('orderby'))->get();
この関数はSQLインジェクションに対して保護されることになっており、唯一の問題はorderBy()関数レベルです。 Laravelのドキュメントによると、この関数はユーザーデータをフィルタリングしないため、この関数を介してSQLインジェクション攻撃が可能です。
最善のことは、ユーザーにテーブル名を制御する可能性を与えないことですが、これが避けられない場合は、ホワイトリストを使用してユーザーデータを検証し、その関数に挿入する必要があります。
SymfonyでSQLインジェクション攻撃を防ぐ方法は?
PHPアプリの開発を加速するための再利用可能なPHPコンポーネントのセットを提供する別のよく知られたPHPフレームワークを見てみましょう。 Symfonyは、DrupalやMagentoのような最も有名なweb CMSのいくつかでも使用されています。
Symfonyはあなたが扱うことができる最も安全なフレームワークの一つであり、安全なコードを書くための幅広い機能を提供しています。 ただし、これらの関数がうまく使用されていない場合は、脆弱なコードが表示されます。 脆弱なコードの例を次に示します:
$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery('SELECT p
FROM App\Entity\Product p
WHERE p.price > '. $request->query->get('price')
);
それでは、この脆弱なコードを分析してみましょう。 Symfonyのドキュメントによると、createQuery()はデフォルトで準備されたステートメントを使用する関数です。 したがって、そのような関数の結果として得られるオブジェクトは、setParameter()関数にアクセスできます。 これは、SQLインジェクションを避けるために、すべてのユーザーデータをフィルタリングします。 これを使用する方法の例を次に示します:
$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery('SELECT p
FROM App\Entity\Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', $price);
CodeigniterでSQLインジェクション攻撃を防ぐ方法は?
CodeIgniter非常に小さなフットプリントを持つ最も強力で軽量で人気のあるPHPフレームワークの一つ。 これは、フル機能のwebアプリケーションを作成するために、シンプルでエレガントなツールキットを必要とする開発者のために構築されました。 SymfonyやLaravelのように、Codeigniterには、開発者がより安全なアプリを作成するのを助けるためのセキュリティシステムもいくつか付属しています。
しかし、Codeigniterでも、一部の開発者は同じ間違いを犯し、フィルタリングせずにユーザーデータを注入します。 SQLインジェクション攻撃につながるこのようなエラーの例を次に示します:
$query = 'SELECT * FROM users WHERE username = '. $this-> input->post('username'). ' AND password= '. $this-> input->post('password');
$this->db->query($query);
この問題を解決するには、Codeigniterのドキュメントを確認する必要があります。 それによると、query()関数は2つのパラメータを取ります。 最初のクエリはsqlクエリで、2番目のクエリはバインドするパラメータです。
例1
デフォルトでは、この関数はバインドされたすべてのパラメーターをフィルター処理して、SQLインジェクションを防ぎます。 この関数を使用する正しい方法の例を次に示します:
$query = 'SELECT * FROM users WHERE username = ? AND password = ? ';
$this->db->query($query, array($this->input->post('username'), $this-> input-> post('password')));
例2:
Codeigniter SQL要求を実行する別の方法を提供すると、SQLインジェクションが防止されます。 Sqlインジェクションを防止するためにActive Recordクラスを使用する例を次に示します:
$this->db->get_where('users',array('username'=>$this->input->post('username') ,'password' => $this->input->post('password')));
CakePHPでSQLインジェクション攻撃を防ぐ方法は?
CAKEPHPは、連想データマッピング、フロントコントローラ、MVCなどの一般的に知られている設計パターンを使用するPHPのための迅速な開発フレームワークです。 CakePHPは、webアプリケーションの開発を容易にするための組み込みコンポーネントの束を提供し、それらをより安全にします。
しかし、CakePHPアプリは、うまく使用されていない場合、SQLインジェクションに対しても脆弱です。 このフレームワークにおけるSQLインジェクション攻撃に対する脆弱なコードの例を次に示します:
$results = $connection-> execute('SELECT * FROM users WHERE username = '. $this->request->getParam('username').' AND password='. $this->request->getParam('password'))->fetchAll('assoc');
execute()関数は、デフォルトで準備されたステートメントを使用します。 ただし、前の例では、ユーザーデータが正当なsql要求に直接挿入されるため、SQLインジェクション攻撃に対して脆弱です。 この関数を使用する正しい方法の例を次に示します:
$results = $connection->execute('SELECT * FROM users WHERE username = :username AND password=:password', )->fetchAll('assoc');
CakePHPフレームワークは、Sqlインジェクション攻撃を防ぐためにユーザーデータのフィルタリングを強制するQuery Builderと呼ばれるシステ CakePHPのドキュメントによると、カバーの下には、クエリビルダは準備された文を使用します。
このようなシステムを正しい方法で使用する方法の例を次に示します:
use Cake\ORM\Locator\LocatorAwareTrait;
$users = $this->getTableLocator()->get('users');
// Start a new query.
$query = $users->find();
$query->where();
FuelPHPでSQLインジェクション攻撃を防ぐ方法は?
FuelPHPは、市場の各フレームワークの最高のアイデアに基づいて生まれた最新のPHPフレームワークの一つです。 これはPHP5で開発され、完全にオブジェクト指向です。 FuelPHPでは、セキュリティは、ユーザーデータをフィルタリングするための多くのセキュリティメカニズムを実装するために、その貢献者をプッシュ SQLインジェクションは、FuelPHPでこのようなメカニズムを実装する理由の一つを攻撃します。
しかし、このような強力なフレームワークであっても、これらのメカニズムの単純な誤用は、SQLインジェクション攻撃のためにコード全体を危険にさらし このようなコードエラーの例を次に示します:
$query = "SELECT * FROM article WHERE id = ". Input::get('id');
$result = DB::query($query)->execute();
これを修正するために、他のフレームワークのような二つの技術もあります。 最初の例は、次の例のようにパラメータをバインドすることによって、query()関数を実際に正しく使用することです:
$query = "SELECT * FROM article WHERE id = :id"; // our query
$result = DB::query($query)->bind('id', Input::get('id'))->execute();
第二の解決策は、fuelphpフレームワークで実装されたORMメカニズムを使用してデータベースと通信することです。 これを使用する方法の例を次に示します:
$user = DB::select()->from('article')->where('id', Input::get('id'))->execute();
zend frameworkでSQLインジェクション攻撃を防ぐ方法は?
Zend framework(Laminas Projectに変更)は、PHPの世界で最も知られているフレームワークの一つです。 これは、それぞれの新しいバージョンが古いものよりもはるかに高速である理由を説明する、心の中でパフォーマンスチューニングで開発されました。 Zendはまた、既知のサイバー脅威に対処するための追加のセキュリティメカニズムを実装するために彼の開発者をプッシュし、最高のセキュリテ
これらのメカニズムのいくつかは、SQLインジェクション攻撃に対処するために実装されました。 しかし、いつものように、これらのメカニズムの誤用は脆弱なコードにつながります。 この記事のこの部分では、このようなエラーの例を示します:
$adapter->query('SELECT * FROM `article` WHERE `id` = '. $this->getRequest()->getPost('id'));
この脆弱性を修正する方法は次のとおりです:
$adapter->query('SELECT * FROM `article` WHERE `id` = ?', );
Leave a Reply