Web の最大の脆弱性は SQL に他なりません。Web バックエンド開発にどの言語が使用されていても、リレーショナル データベースが使用されている限り、SQL インジェクション攻撃に遭遇する可能性があります。では、SQL インジェクションは Python Web 開発中にどのように発生し、この問題をどのように解決するのでしょうか?
もちろん、他の言語で SQL インジェクションを回避する方法については議論したくありません。PHP インジェクションの防止については、インターネット上にさまざまな方法がありますが、ここでは例を示します。
脆弱性の最も一般的な原因は文字列のスプライシングです。もちろん、SQL インジェクションは単なるスプライシングのケースではなく、ここで説明したワイド バイト インジェクション、特殊文字エスケープなど、他にも多くの種類があります。最も一般的な文字列の連結と言えば、これはジュニア プログラマーにとって最も一般的な間違いでもあります。
まず、mysqlの操作を処理するクラスを定義します
class Database: hostname = '127.0.0.1' user = 'root' password = 'root' db = 'pythontab' charset = 'utf8' def __init__(self): self.connection = MySQLdb.connect(self.hostname, self.user, self.password, self.db, charset=self.charset) self.cursor = self.connection.cursor() def insert(self, query): try: self.cursor.execute(query) self.connection.commit() except Exception, e: print e self.connection.rollback() def query(self, query): cursor = self.connection.cursor(MySQLdb.cursors.DictCursor) cursor.execute(query) return cursor.fetchall() def __del__(self): self.connection.close()
このクラスに問題はありますか?
答えは「はい」です。
このクラスには欠陥があり、SQL インジェクションが簡単に発生する可能性があります。なぜ SQL インジェクションが発生するのかについて説明します。
問題の真偽を確認するために、エラーが発生した場合に上記のクラスのメソッドを直接呼び出す方法を示します。
def test_query(testUrl): mysql = Database() try: querySql = "SELECT * FROM `article` WHERE url='" + testUrl + "'" chanels = mysql.query(querySql) return chanels except Exception, e: print e
このメソッドは非常に単純です。最も一般的な選択クエリ ステートメントの 1 つは、SQL ステートメントを形成するために最も単純な文字列連結を使用します。注入テストを実行する場合は、渡されるパラメーター testUrl が制御可能であることは明らかです。これを testUrl に追加するだけです。値の後に一重引用符を追加することで SQL インジェクション テストを実行できます。言うまでもなく、インジェクションの脆弱性があるはずです。スクリプトを実行して結果を確認してください
(1064, "You SQL 構文にエラーがあります。MariaDB サーバーのバージョンに対応するマニュアルで、行 1 の「t.tips」付近で使用する正しい構文を確認してください。)
エラー メッセージがエコーされます。これはよくあるエラーです。ここで渡したテストパラメータは
tです。ヒント
上記のメソッドを少し変更した後、別の状況について説明します
def test_query(testUrl): mysql = Database() try: querySql = ("SELECT * FROM `article` WHERE url='%s'" % testUrl) chanels = mysql.query(querySql) return chanels except Exception, e: print e
このメソッドは文字列のスプライシングを直接使用しません。渡されるパラメータを置き換えます。プリコンパイルされた SQL に非常によく似ているようです。この書き方でSQLインジェクションを防ぐことはできるのでしょうか?テストしてみるとわかります。応答は次のとおりです
(1064, "SQL 構文にエラーがあります。"t.tips 付近で使用する正しい構文については、MariaDB サーバーのバージョンに対応するマニュアルを確認してください。 ''' 行 1")
結果は上記のテストと同じであるため、この方法は不可能であり、この方法は SQL ステートメントをプリコンパイルしません。では、SQL インジェクションを防ぐにはどうすればよいでしょうか?
2 つの解決策
1> 受信パラメータをエンコードしてエスケープする
2> Python の MySQLdb モジュールに付属するメソッドを使用する
1 つ目の解決策は、実際に多くの PHP アンチインジェクションメソッドで使用されます。エスケープまたはフィルタリングされます。
2 番目のオプションは、PHP の PDO に似た内部メソッドを使用することです。ここでは、上記のデータベース クラスを単純に変更できます。
修正コード
class Database: hostname = '127.0.0.1' user = 'root' password = 'root' db = 'pythontab' charset = 'utf8' def __init__(self): self.connection = MySQLdb.connect(self.hostname, self.user, self.password, self.db, charset=self.charset) self.cursor = self.connection.cursor() def insert(self, query, params): try: self.cursor.execute(query, params) self.connection.commit() except Exception, e: print e self.connection.rollback() def query(self, query, params): cursor = self.connection.cursor(MySQLdb.cursors.DictCursor) cursor.execute(query, params) return cursor.fetchall() def __del__(self): self.connection.close()
execute が実行されると、2 つのパラメータが渡されます。1 つ目はパラメータ化された SQL ステートメントで、2 つ目は対応する実際のパラメータ値です。渡されたパラメータ値は関数の内部で処理されます。 SQLインジェクションを防ぐために該当する処理を行う実際のメソッドは以下の通りです
preUpdateSql = "UPDATE `article` SET title=%s,date=%s,mainbody=%s WHERE id=%s"
mysql。 insert(preUpdateSql , [title, date, content, aid])
これにより、SQL インジェクションを防ぐことができます。リストを渡した後、MySQLdb モジュールは内部でリストをタプルにシリアル化し、エスケープ操作を実行します。
以上がSQLインジェクションを防ぐPythonの方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。