Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用“SELECT*FROM{table_name}”避免SQL注入?_Python_Sql_Postgresql_Sql Injection_Psycopg2 - Fatal编程技术网

Python 如何使用“SELECT*FROM{table_name}”避免SQL注入?

Python 如何使用“SELECT*FROM{table_name}”避免SQL注入?,python,sql,postgresql,sql-injection,psycopg2,Python,Sql,Postgresql,Sql Injection,Psycopg2,在Python中使用Psycopg2和以下代码: import psycopg2 import getpass conn = psycopg2.connect("dbname=mydb user=%s" % getpass.getuser()) cursor = conn.cursor() tables = ["user", "group", "partner", "product"] for table in tables: # with sql injection c

在Python中使用Psycopg2和以下代码:

import psycopg2

import getpass

conn = psycopg2.connect("dbname=mydb user=%s" % getpass.getuser())
cursor = conn.cursor()

tables = ["user", "group", "partner", "product"]
for table in tables:

    # with sql injection
    cursor.execute("SELECT name FROM %s LIMIT 1" % (table,))
    print "table", table, "result", len(cursor.fetchone())

    # without sql injection
    cursor.execute("SELECT name FROM %s LIMIT 1", (table,))
    print "table", table, "result", len(cursor.fetchone())
结果是:

table res_partner result 1
Traceback (most recent call last):
  File "my_psycopg2_example.py", line 16, in <module>
    cursor.execute("SELECT name FROM %s LIMIT 1", (table,))
psycopg2.ProgrammingError: syntax error at or near "'res_partner'"
LINE 1: SELECT name FROM 'res_partner' LIMIT 1
使用SQL注入,它可以正常工作

但我们不想制造安全问题

我们在阅读中发现了以下评论:

只能通过此方法绑定变量值:它不应用于设置表名或字段名。对于这些元素,在运行execute之前应使用普通字符串格式

但是如果我们使用普通的字符串格式,我们也会有SQL注入


管理这种特殊情况并避免SQL注入的好方法是什么?

我认为您混淆了SQL注入的定义。SQL注入是对您的软件的一种攻击,其中有人导致您的SQL查询执行您不希望执行的操作。字符串插值不是SQL注入。字符串插值有时可以启用SQL注入,但并不总是如此。要了解字符串插值并不总是不安全的,请考虑以下哪项最安全:

sql='从用户中选择名称' sql='从'+'用户'中选择名称' sql='从%s%['用户']中选择名称 sql='从{}中选择名称'。格式为'user' 这些代码行中的每一行都做着完全相同的事情,因此没有一行代码比其他代码更安全。在您的示例中,没有SQL注入的危险,因为您只是构建一个硬编码的SQL查询字符串

另一方面,如果表值来自用户,则可能存在安全问题:

如果他们传递了一个已存在的表的名称,但您不希望他们查询,该怎么办

table = 'secrets'
sql = 'SELECT name FROM %s LIMIT 1' % table
结果:

SELECT name FROM secrets LIMIT 1
SELECT name FROM product;
DROP TABLE user;
-- LIMIT 1
如果他们传递的不是实际的表名呢

table = 'product; DROP TABLE user; --'
sql = 'SELECT name FROM %s LIMIT 1' % table
结果:

SELECT name FROM secrets LIMIT 1
SELECT name FROM product;
DROP TABLE user;
-- LIMIT 1
您可以通过检查是否允许使用表名来防止这种情况:

if table.lower() not in ["user", "group", "partner", "product"]:
    raise Something('Bad table name: %r' % table)

在execute函数中使用psycopg2查询参数是最安全的,当参数用作文本时,使用起来也很方便

cursor.mogrify("select * from foo where bar = %s", ('example',))
# yields "select * from foo where bar = 'example'"
请注意,cursor.mogrify的行为类似于execute,但只是显示格式化的SQL,而没有实际执行它

然而,当您希望参数是表、模式或其他标识符时,这就有点棘手了。您可以使用AsIs包装参数,但这仍然为SQL注入打开了大门

from psycopg2.extensions import AsIs

cur.mogrify('select %s from foo;', (AsIs('* from dual; drop table students; --'),))
# yields 'select * from dual; drop table students; -- from foo;'
看起来psycopg2>=2.7的新开发将有一个标识符类,您可以将参数封装在其中,希望是安全的。如果它还没有发布,或者您还没有,这里有一种方法可以创建您自己的类。我将在下面给出一些片段,但您也可以看到

如果您已经有一个psycopg2游标实例,可以通过以下方式测试/使用它:

# Test that a valid identifier formats into string
cursor.mogrify('select %s from foo;', (QuotedIdentifier('bar'),))
# returns 'select bar from foo;'

# Test formatting both an identifier and a literal
cursor.mogrify(
    'select * from foo where %s = %s;', 
    (
        QuotedIdentifier('bar'),
        'example'
    )
)
# returns "select * from foo where bar = 'example';"

# Test that a non-valid identifier fails with exception
cursor.mogrify('select %s from foo;', (QuotedIdentifier('* from dummy; drop table students; --'),))
"""Returns following:
---------------------------------------------------------------------------
NotSqlIdentifierError                     Traceback (most recent call last)
<ipython-input-14-d6a960dc458a> in <module>()
----> 1 cur.mogrify('select %s from foo;', (QuotedIdentifier('* from dummy; drop table students; --'),))
<ipython-input-12-0a1327cbaf78> in getquoted(self)
     18             return self.obj_str
     19         else:
---> 20             raise NotSqlIdentifierError(repr(self.obj_str))
     21 
     22 psycopg2.extensions.register_adapter(QuotedIdentifier, lambda x: x)
NotSqlIdentifierError: '* from dummy; drop table students; --'
"""

有关包装SQL参数的自定义类机制的更多信息,请参阅文档中的。

我认为您的代码可能缺少;。您的一行代码可能如下所示:

cursor.execute('SELECT name FROM %s LIMIT 1;', (table,))
如果所有其他操作都失败,您可以为该输入设置一个过滤器,以去除控制字符。对我来说听起来很痛苦,但你要有能力。然后,您的代码将类似于:

cursor.execute('SELECT name FROM %s LIMIT 1;' % (functionToSanitizeInput(table)))
也许您可以使用此项目:

================================================

非常好的参考:


====================================================

这是一篇关于注入和python代码的好文章

你可以改变

tables = ["user", "group", "partner", "product"]
for table in tables:    
    cursor.execute("SELECT name FROM %s LIMIT 1" % (table,))


@moylop260这是您的真实示例,还是表来自真实代码中的其他地方?因为在本例中,表来自代码中的一个常量,所以不存在安全问题。