SQL注入は非常に単純な攻撃方法ですが、今日でも非常に一般的です。その理由は、愚かなパッチはありません。なぜそれを言うのですか? Javaを例として説明しましょう。
データベースにこのようなテーブルがあるとします。
テーブルユーザー(ID varchar(20)プライマリキー、名前Varchar(20)、Age Varchar(20));
次に、JDBCを使用してテーブルを操作します。
private string getNameByUserID(String userId){connection conn = getConn(); // get connection string sql = "ユーザーから[名前] where id =" + userid; preatedStatement pstmt = conn.preparestatement(sql);結果rs = pstmt.executeupdate(); ......}上記のコードは、一部の開発者によってよく使用されます。この状況を想像してください。渡されたユーザーIDパラメーターが「3、ドロップテーブルユーザー」の場合、実行されたSQLステートメントは次のとおりです。
id = 3でユーザーから名前を選択します。ドロップテーブルユーザー。
データベースがコンパイルされて実行されると、ユーザーテーブルが削除されます。ほら、簡単なSQLインジェクション攻撃が有効です!これは、上記のコードがプログラミング仕様に準拠していないためです。
仕様に応じてプログラムする場合、SQL注入は存在しません。これは、SQLインジェクションを回避する最初の方法でもあります。事前拡張されたステートメント、コードは次のとおりです。
接続conn = getConn(); //接続文字列sql = "ユーザーから名前を選択するwhere id =?"; preatedStatement pstmt = conn.preparestatement(sql); pstmt.setString(1、userid);結果rs = pstmt.executeupdate(); ...
上記のコードにSQLインジェクションが存在しないのはなぜですか?事前コンパイルされたステートメントが使用されるため、事前コンパイルされたステートメントには、「id =??事前に実行するときは、実行するときは、それを渡されたパラメーターに置き換える必要がありますか?プレースホルダー。仕様に準拠していない最初のケースでは、プログラムはSQLステートメントを作成し、ユーザーが渡すコンテンツでそれらをコンパイルします。これがまさに問題です。
事前コンパイルされたステートメントを使用することに加えて、SQLインジェクション攻撃を回避する2番目の方法があります:ストアドプロシージャ。ストアドプロシージャは、特定の機能を完了するSQLステートメントのセットです。コンパイル後、データベースに保存されます。ユーザーは、ストアドプロシージャを呼び出してパラメーターを提供することで実行できます(ストアドプロシージャにパラメーターがある場合)。また、SQLインジェクション攻撃を回避することもできます。
接続conn = getConn(); stmt = conn.preparecall( "{call name_from_user(?、?)}"); stmt.setint(1,2); stmt.registeroutParameter(2、Types.Varchar); stmt.execute();文字列名= stmt.getString(2);上記のコードの対応するストアドプロシージャは次のとおりです。
ユーザーを使用してください。 delimiter //プロシージャname_from_userの作成(user_id int、out user_name varchar(20))begin name into user_name from user from user where id = user_id; End // Delimiter;
もちろん、ユーザーはフロントエンドでキャラクターチェックを行うこともできます。これは、SQLインジェクションを回避する方法でもあります。たとえば、上記のユーザーIDパラメーターの場合、ユーザーはセミコロンが含まれていることを確認するときにエラーをプロンプトします。
ただし、最も基本的な理由から、アプリはデータベースにアクセスするときに最小許可を使用しないため、SQLインジェクション攻撃が存在します。そう、誰もがルートアカウントを使用してデータベースにアクセスしているようです。
では、MyBatisはどのようにしてSQLインジェクション攻撃を避けますか?上記のテーブルユーザーを例として使用しましょう。
マッパーファイルは次のとおりです。
<選択id = "getnameByuserid" resultType = "string">ユーザーから名前を選択するwhere id =#{userId} </select>対応するJavaファイルは次のとおりです。
public interface usermapper {string getnameByuserid(@param( "userid")string userid); }入力パラメーターが文字列タイプのユーザーIDであることがわかります。 userid = "34;ドロップテーブルユーザー;"を渡すと "印刷されたステートメントは次のとおりです。
id =?
どのユーザーIDが入力されていても、彼のSQLステートメントはこのようなものです。これは、基礎となる実装における事前コンパイルされたステートメントの使用によるものです。データベースがこのステートメントを実行すると、事前コンパイルされたステートメントを直接使用し、プレースホルダーを渡されたユーザーIDに置き換えますか?走るだけです。最初にプレースホルダーを交換するために存在しませんか?編集プロセスが実行されるため、SQL注入の生存の余地はありません。
では、MyBatisはどのようにしてSQLの事前コンパイルを達成しますか?実際、フレームワークは準備クラスを使用しています。準備されたクラスは、SQL注入を回避するだけではありません。同じSQLステートメントがn回実行されると、コンピレーション時間を節約し、それにより効率が向上します。
上記のステートメントを変更した場合:
<select id = "getnameByuserid" resultType = "string">ユーザーから名前を選択するwhere id = $ {userId} </select> userId="34;drop table user;"を入力すると、 " 、印刷されたステートメントは次のようになります:
id = 34;ドロップテーブルユーザーからユーザーから名前を選択します。
現時点では、MyBatisは事前縮小されたステートメントを使用していません。最初に文字列ステッチを実行し、次にコンパイルを実行します。このプロセスは、SQLインジェクションが有効になるプロセスです。
したがって、MyBatisマッピングステートメントを書くときは、フォーマット「#{xxx}」を使用してみてください。 「$ {xxx}」のようなパラメーターを使用する必要がある場合は、SQL注入攻撃を防ぐために手動でフィルタリングを行う必要があります。
要約します
上記は、あなたに紹介されたMyBatisによるSQL注射を防ぐ方法の詳細な説明です。それがあなたに役立つことを願っています。ご質問がある場合は、メッセージを残してください。編集者は時間内に返信します。 wulin.comのウェブサイトへのご支援ありがとうございます!