用拼接字符串方式构造SQL语句比较容易犯sql注入问题。
常见的防范方式是以参数传入的方式处理,(把参数通过数据库提供的接口传入数据库,在数据库里面处理,而不是在数据库外面拼接SQL语句)
python 中一般是在游标执行execute时传递参数
uid=123
pwd='bb987#$!~EE'
args = (uid, pwd)
cur.execute('select * from user_table where uid = %s and pwd = %s', args )
注意:
对于传入的字符串类型的参数,在构造sql语句的模板上不需要加引号,mysql会自动转义及加引号的。
但对于string.format(参数值,参数值) 和 string % (参数值,参数值) 方式先把sql生成好再直接执行的方式,是需要手动加引号的。
uid=100
pwd='976$#@387'
cur.execute(“select * from user_table where uid = %s and pwd = %s”, (uid,pwd) )
# 上面这句pwd位置不需要加引号,sql模板和值之间是用逗号【分隔】。
# 下面这句pwd位置需要加引号, sql模板和值之间是用百分号【连接】。
cur.execute(“select * from user_table where uid = %s and pwd = '%s'” % (uid,pwd) )
但QT5的QsqlQuery的exec函数不支持这种方式。提示:too many arguments
建议使用QSqlQuery.prepare 官方文档:
QSqlQuery — Qt for Python
在PyQt中,prepare()可以保护你免受SQL注入攻击,当你的SQL语句含有不可信输入时,推荐使用prepare。
exec(QString query): 执行query查询语句。查询执行后,必须通过使用next()等函数,定位到一个有效的记录,才能读取数据库记录。
prepare(QString query): 准备SQL查询语句。适用于带参数的查询语句。查询代码中的参数可以用ODBC样式(问号)或Oracle样式(符号前面加冒号)来指定,但是它们不能混合在同一个查询中。
addBindValue(QVariant val[, QSql.ParamType paramType = QSql.In]):使用位置值绑定时,将值val添加到值列表中。 addBindValue( )调用的顺序决定了此值 绑定到prepare()函数参数中的哪个占位符。
可选参数paramType 默认值为QSql.In,表明是往数据库中写入数据;
QSql.Out为从数据库中读出数据;
QSql.InOut为往数据库中写入数据,但执行exec()后,会被读出的数据覆盖。
要绑定NULL值,请使用空QVariant;例如,如果要绑定字符串,请使用QVariant(QVariant::String)。
bindValue(int pos, const QVariant val, QSql.ParamType paramType = QSql.In):指定prepare()函数参数中的pos占位符的值为val。pos=0代表第一个占位符。
bindValue
(placeholder, val[, type=QSql.In])
传入参数值的方法有两个:addBindValue() 和 bindValue() 区别在于addBindValue()必须严格按照顺序传入,bindValue()可以不按顺序,因为通过pos参数 或 placeholder参数指定了传给谁。
# addBindValue(const QVariant val, QSql.ParamType paramType = QSql.In):调用的顺序决定了此值 绑定到prepare()函数参数中的哪个占位符。
query.prepare ("insert into good values (null,?,?)")
query.addBindValue ('Floppy')
query.addBindValue (10)
query.exec()
# bindValue(int pos, const QVariant val, QSql.ParamType paramType = QSql.In):指定prepare()函数参数中的pos占位符的值为val。pos=0代表第一个占位符。
query.prepare ("insert into good values (null,?,?)")
query.bindValue (0, 'Floppy')
query.bindValue (1, 10)
query.exec()
# bindValue(QString placehold, const QVariant val, QSql.ParamType paramType = QSql.In):指定prepare()函数参数中的placehold占位符的值为val。
query .prepare("insert into good values(null, :name, : count )")
query.bindValue(":name", 'Floppy')
query.bindValue(":count", 10)
query.exec()
# exec():执行prepare()中的SQL语句。 如果执行成功,返回True; 否则,返回False。
官方文档代码example:
query = QSqlQuery()
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)")
query.bindValue(":id", 1001)
query.bindValue(":forename", "Bart")
query.bindValue(":surname", "Simpson")
query.exec_()
补充:
经测试,同一个QSqlQuery对象,重新执行prepare后,之前绑定的value就全部失效了。
但在不重新执行prepare情况下,重新绑定value,然后重新执行exec_(),会得到新的结果。
sql="select * from user_table where id=?"
myQuery =QSqlQuery()
myQuery.prepare(sql)
myQuery.addBindValue(100)
myQuery.exec_()
while myQuery.next():
print(myQuery.value('user_name'))
# 没有重新prepare,直接重新addBindValue,再次执行exec_(),得到新结果
myQuery.addBindValue(102)
myQuery.exec_()
while myQuery.next():
print(myQuery.value('user_name'))