Python 准备好的陈述,谁是正确的?

Python 准备好的陈述,谁是正确的?,python,mysql,security,pymysql,Python,Mysql,Security,Pymysql,我已经创建了一个名为test的测试数据库,它有一个名为testTable的表,带有一个autoincrement id值和一个接受varchar(30)的name字段 PREPARE语句查询(其中4个)在复制到phpmyadmin时执行良好,但我得到了错误我从pymysql的开发人员那里发现库不支持PREPARE mysql语句。此外,pymysql库默认情况下不执行多语句 我知道,如果启用了多个语句,我第一次尝试将值替换到INSERT语句中本质上是不安全的。这可以通过在connect构造函数中

我已经创建了一个名为test的测试数据库,它有一个名为testTable的表,带有一个autoincrement id值和一个接受varchar(30)的name字段


PREPARE语句查询(其中4个)在复制到phpmyadmin时执行良好,但我得到了错误我从pymysql的开发人员那里发现库不支持PREPARE mysql语句。此外,pymysql库默认情况下不执行多语句

我知道,如果启用了多个语句,我第一次尝试将值替换到INSERT语句中本质上是不安全的。这可以通过在connect构造函数中使用client_flag=pymysql.constants.client.MULTI_语句来实现

然而,pymysql库允许使用cursor.execute(query,(tuple))方法在MySQL查询中使用占位符

为了演示这一点,我编写了以下测试代码示例

import pymysql
import logging

class TestClass():

    def __init__(self):
        # mysqlconnections

        self.mySQLHostName = "localhost"
        self.mySQLHostPort = 3306
        self.mySQLuserName = "name"
        self.mySQLpassword = "pw"
        self.MySQLauthchandb = "mysql"
        
    def QueryMYSQL (self, query, data = ()):
        try:
            logging.info("QueryMYSQL  : " + str( query)) # Uncomment to print all mysql queries sent
            conn = pymysql.connect(host=self.mySQLHostName, port=self.mySQLHostPort, user=self.mySQLuserName, passwd=self.mySQLpassword, db=self.MySQLauthchandb, charset='utf8', client_flag=pymysql.constants.CLIENT.MULTI_STATEMENTS) #code injection requires multistatements to be allowed this is off in pymysql by default and has to be set on manually. 
            conn.autocommit(True)
            cursor = conn.cursor()
            if cursor:
                if data:
                    returnSuccess = cursor.execute(query, data)
                else:
                    returnSuccess = cursor.execute(query)
                
            if cursor:
                returnValue = cursor.fetchall()
            logging.info ("return value : " + str(returnValue)) # Uncomment to print all returned mysql queries
            if cursor:
                cursor.close()
            if conn:
                conn.close()
            return returnValue
        except Exception as e:
            logging.error("Problem in ConnectTomySQL")
            logging.error(e)
            logging.error(query)
            if data:
                logging.error("Data {}".format(str(data)))
            return False

# Default error logging log file location:
logging.basicConfig(format='%(asctime)s (%(threadName)-10s) [%(levelname)s] %(message)s', filename= 'ERROR.log',filemode = "w", level=logging.DEBUG)
logging.info("Logging Started")

def usePlaceholder(userInput):
    query = "INSERT INTO test.testTable (id, name) VALUES (NULL , %s)"
    data = (userInput,) 
    result = test.QueryMYSQL(query,data)
    print(result)

def useSubstitution(userInput):
    query = "INSERT INTO test.testTable (id, name) VALUES (NULL , '{}')".format(userInput) # this is unsafe.
    result = test.QueryMYSQL(query)
    print(result)

test = TestClass()

#Create the test database and testTable.
query = "CREATE DATABASE test"
test.QueryMYSQL(query)
query = "CREATE TABLE `test`.`testTable` ( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(256) NULL DEFAULT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;"
test.QueryMYSQL(query)

#Simulated user input.
legitUserEntry = "Ringo"
injectionAttempt = "333' ); INSERT INTO test.testTable (id, name) VALUES (NULL , 666);#" #A simulated user sql injection attempt.

useSubstitution(legitUserEntry) # this will also insert Ringo - but could be unsafe.
usePlaceholder(legitUserEntry) # this will insert Ringo - but is safer.

useSubstitution(injectionAttempt) # this will inject the input code and execute it. 
usePlaceholder(injectionAttempt) # this will insert the input into the database without executing the injected code.

因此,在本练习中,我将通过将multi语句设置为off(默认设置)并使用占位符和数据元组而不是替换来提高安全性。

这可能是指准备好的语句模拟,但我不熟悉所讨论的Python驱动程序的内部结构。如果您在驱动程序级别使用占位符值,而不进行模拟,则应该可以。如果涉及到仿真,那么该实现中可能存在bug或限制。我认为这里的问题是您没有指定导致问题的
分隔符。我根本不相信这个MySQL代码。您正在连接并运行一条语句。这是非常低效的,甚至不能扩展到最琐碎的用例之外。是的,使用多查询没有任何好处,并且当多查询生效时,不支持真正的预处理语句。保持简单:每次调用一条SQL语句,并使用参数。