SQL 清理 python [重复]

SQL sanitize python [duplicate]

提问人:Learning from masters 提问时间:3/24/2022 更新时间:3/24/2022 访问量:3730

问:

在使用 python 时,清理 SQL 以防止注入的最佳方法是什么?我正在使用mysql-connector。我已经读到我应该使用类似于以下内容的结构:

import mysql.connector

connection = mysql.connector.connect(host="", port="", user="", password="", database="")
cursor = connection.cursor( buffered = True )

sql = "INSERT INTO mytable (column1, column2) VALUES (%s, %s)"
val = (myvalue1, myvalue2)

cursor.execute(sql, val)
connection.commit()

但是,我不明白为什么这会阻止注射。这够了吗?用户可以在 myvalue1 或 myvalue2 上向我介绍任何内容,即使它不应该这样做。有什么有用的图书馆吗?

python mysql sql 代码注入

评论

1赞 Charles Duffy 3/24/2022
消毒是完全错误的方法。完全停止混合数据和代码;使用绑定变量将数据保持在带外。
1赞 Charles Duffy 3/24/2022
你已经这样做了,所以你很好。设计得更好的数据库,我上次知道MySQL不是,甚至在有线协议级别上将数据和参数彼此分开,甚至超越解析器。
1赞 deceze 3/24/2022
@Charles 你在那里有点过时了,MySQL本身支持准备好的语句就好了: dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
0赞 Bill Karwin 3/24/2022
@deceze,Python 连接器有一些特殊的注意事项。默认情况下,它模拟准备好的语句,但实际上执行字符串插值。必须使用游标的子类才能获得真正的预准备语句。
1赞 Bill Karwin 3/24/2022
@CharlesDuffy 在20年内,大多数技术都可以改进(例外:Microsoft Windows)。所有技术都有疣——甚至 PostgreSQL。

答:

1赞 Bill Karwin 3/24/2022 #1

当不受信任的输入入到 SQL 查询中并且输入包含更改查询语法的字符时,SQL 注入将起作用。

查询参数与 SQL 查询分开,从不插入其中。参数的值在解析与 SQL 查询合并,因此不再有任何更改语法的机会。该参数保证被视为单个标量值(即,就好像它只是 SQL 表达式中的字符串文字一样)。

如果使用 cursor 子类,这就是 Python 连接器的工作方式。查看 https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursorprepared.htmlMySQLCursorPrepared

否则,Python 连接器将“模拟”准备好的查询。它实际上在解析 SQL 查询之前将参数插值到 SQL 查询中,但它通过转义会导致 SQL 注入的特殊字符来安全地这样做。它经过充分测试,因此很可靠。

两种游标类型的使用方式相同,传递一个带有占位符的 SQL 查询字符串,以及另一个带有参数值元组的参数。您正在正确使用它。%s


来自@Learningfrommasters的回复:

是的,存储在数据库中的字符串可能会在另一个 SQL 查询中不安全地使用,并导致 SQL 注入。有些人认为只有用户输入必须得到安全处理,但事实并非如此。任何变量都应被视为查询参数,无论该变量的值来自用户输入,还是从文件中读取,甚至是从您自己的数据库中提取。

示例:假设我的名字是 Bill O'Karwin。它有一个撇号,你知道它是 SQL 的一个特殊字符,因为它终止了一个字符串文字。

如果我的名字存储在数据库中,然后以变量的形式提取到应用程序中,那么我可以搜索具有相同姓氏的其他人:userlastname

sql = f"SELECT * FROM Users WHERE lastname = '{userlastname}'"

这是不安全的,因为撇号会导致SQL注入。尽管该值不是直接来自用户输入,但它来自我自己的数据库。

因此,对所有变量使用参数。然后,您不必考虑来源是否安全。

sql = "SELECT * FROM Users WHERE lastname = %s"
cur.execute(sql, (userlastname,))

评论

0赞 Learning from masters 3/24/2022
那么我有一个问题:想象一下有人引入了一个不好的值,这可能会导致注射。因为我做了之前的解决方案,所以它不会进行注射。但是,它将存储为字符串。如果以后我必须对该表进行选择,该字符串是否能够注入任何内容?
0赞 deceze 3/24/2022
@Learning 仅当您以后错误地处理该存储值时:en.wikipedia.org/wiki/SQL_injection#Second_order_SQL_injection
1赞 Charles Duffy 3/24/2022
@Learningfrommasters,试图在进入的途中“清理”数据意味着你把所有的防御都放在一个地方,如果有什么东西越过了它们,战斗就输了。该行业长期以来一直试图打这场外围战,并一次又一次地失败(尤其是当显示层及其清理需求随着时间的推移而变化时)。然而,如果你让你处理或呈现数据的每个地方都以安全、适合上下文的方式处理它,那么边界之争就变得毫无意义了。这很像零信任与防火墙模型的类似物。
0赞 Charles Duffy 3/24/2022
@Learningfrommasters,...回到我所说的关于清理需求和显示层的内容:将某些东西清理为在JSON中时是安全的,这与将其清理为在替换到HTML时是安全的不同,这与将其清理为在替换到SQL时是安全的不同,等等。你不能一次打完所有这些仗并获胜;最好确保你的HTML渲染将数据转义为HTML,将数据替换为JSON的代码将其转义为JSON,等等 - 那么它就不是输入层的工作。
0赞 Charles Duffy 3/24/2022
@Learningfrommasters,...我可以写文章,而且我写过,关于即使是非常大的行业参与者如何从对他们的攻击中吸取错误的教训,并以无效的方式做出反应。可以说,上面的段落反映了昂贵的学习经验。