Python参数传递以防止sql注入。为什么会出错?

时间:2011-02-17 22:36:51

标签: python oracle

from django.db import connection, transaction

def pk_dt_catalog(p_CAT_ID,p_COMMONS_ID):

    c1 = connection.cursor()
    sql = "SELECT COMMONS_ID, CAT_ID, CAT_NAME 
             FROM DT_CATALOG"

    sql = sql + " WHERE CAT_ID = %s 
                    AND COMMONS_ID = %s "

    param =(p_CAT_ID, p_COMMONS_ID)
    c1.execute(sql, param)
    return c1


>>> c = dt_catalog.pk_dt_catalog(513704,401)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "dt_catalog.py", line 24, in pk_dt_catalog
    c1.execute(sql,(p_CAT_ID, p_COMMONS_ID,))
cx_Oracle.DatabaseError: ORA-01036: illegal variable name/number

1 个答案:

答案 0 :(得分:10)

在你的代码中,你正在使用%s这是python substition字符串语法,它需要在同一行上的替换值,例如

sql = sql + " WHERE CAT_ID = %s
                AND COMMONS_ID = %s " % (p_CAT_ID, p_COMMONS_ID)

然而,这(如前所述)并不是最好的方法,因为(a)它可能是一个SQL注入漏洞; (b)由于每次调用都需要对新SQL语句进行硬解析,因此可能会导致数据库性能不佳。

相反,您应该使用Oracle Bind变量语法,例如:

c1 = connection.cursor()
sql = "SELECT COMMONS_ID, CAT_ID, CAT_NAME 
         FROM DT_CATALOG"

sql = sql + " WHERE CAT_ID = :foo 
                AND COMMONS_ID = :bar "

param = (p_CAT_ID, p_COMMONS_ID)
c1.execute(sql, param)
return c1

更多信息:http://guyharrison.squarespace.com/blog/2010/1/17/best-practices-with-python-and-oracle.html

上面的示例使用位置绑定,即第一个参数绑定到第一个绑定占位符,列表中的第二个参数绑定到第二个占位符。

更好的方法是使用dict按名称为特定绑定变量赋值。当很难知道占位符添加到查询中的顺序,并使代码更易于阅读和维护时,这非常有用:

c1 = connection.cursor()
sql = "SELECT COMMONS_ID, CAT_ID, CAT_NAME 
         FROM DT_CATALOG"

sql = sql + " WHERE CAT_ID = :foo 
                AND COMMONS_ID = :bar "

param = {"foo": p_CAT_ID, "bar": p_COMMONS_ID}
c1.execute(sql, param)
return c1

更多示例和教程:http://st-curriculum.oracle.com/obe/db/11g/r2/prod/appdev/opensrclang/pythonhol2010_db/python_db.htm