Python中防止SQL注入的方法详解

落日邮差
落日邮差
发布时间:2026-10-13| 3人浏览过
原创

本文深入解析Python Web开发中SQL注入漏洞的成因,重点对比字符串拼接与占位符用法的差异。通过实际代码示例展示错误用法导致的语法报错,并给出基于MySQLdb模块的参数化查询解决方案,帮助开发者有效防御SQL注入攻击。

前言

在当前的Web安全领域,SQL注入长期位居漏洞榜首。无论后端开发采用何种编程语言,只要涉及关系型数据库的使用,就不可避免地面临SQL注入攻击的风险。本文旨在探讨在Python Web开发环境中,SQL注入是如何产生的,以及应采取何种措施来有效解决这一问题。

本文不讨论其他编程语言(如PHP,网络上关于其防注入方法的讨论众多)的具体实现,而是聚焦于Python。尽管Python的防注入思路与PHP类似,但本文将通过具体案例进行详细说明。

起因

SQL注入漏洞最典型的成因是字符串拼接。虽然宽字节注入、特殊字符转义不当等也是注入途径,但字符串拼接是初级开发者最容易犯的错误,也是本文讨论的重点。

首先,我们定义一个用于处理MySQL操作的类。

class Database:
 aurl = '127.0.0.1'
 user = 'root'
 password = 'root'
 db = 'testdb'
 charset = 'utf8'

 def __init__(self):
  self.connection = MySQLdb.connect(self.aurl, self.user, self.password, self.db, charset=self.charset)
  self.cursor = self.connection.cursor()

 def insert(self, query):
  try:
   self.cursor.execute(query)
   self.connection.commit()
  except Exception, e:
   print e
   self.connection.rollback()

 def query(self, query):
  cursor = self.connection.cursor(MySQLdb.cursors.DictCursor)
  cursor.execute(query)
  return cursor.fetchall()

 def __del__(self):
  self.connection.close()

这段代码常见于我过往的许多脚本中,凡是涉及Python操作MySQL数据库的脚本,通常都会包含此类封装。然而,这个类是否存在问题?答案是有缺陷的。

该类存在明显的安全缺陷,极易导致SQL注入。下文将详细分析其产生注入的原因。

为了验证问题的真实性,我们编写一个调用上述类中方法的功能函数。若执行过程中出现错误,将直接抛出异常。

def test_query(articleurl):
 mysql = Database()
 try:
  querySql = "SELECT * FROM `article` WHERE url='" + articleurl + "'"
  chanels = mysql.query(querySql)
  return chanels
 except Exception, e:
  print e

该方法实现了一个最常见的SELECT查询语句,并使用了最基础的字符串拼接方式构建SQL。显然,传入的参数articleurl是可控的。要进行注入测试,只需在articleurl的值后添加单引号即可。这显然存在注入漏洞,让我们运行脚本查看结果。

(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''t.tips''' at line 1")

系统回显了报错信息,这是一个非常熟悉的错误。这里我传入的测试参数是

t.tips'

接下来介绍另一种导致注入的情况,对上述方法稍作修改后:

def test_query(articleurl):
 mysql = Database()
 try:
  querySql = ("SELECT * FROM `article` WHERE url='%s'" % articleurl)
  chanels = mysql.query(querySql)
  return chanels
 except Exception, e:
  print e

此方法未直接使用字符串拼接,而是使用%s作为参数占位符,看起来似乎类似于预编译SQL。但这种写法能否防止SQL注入?通过测试可知,回显结果如下:

(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''t.tips''' at line 1")

测试结果与前述情况一致,说明这种方法同样无法防止SQL注入。此外,这种写法并非真正的预编译SQL语句。那么,究竟该如何正确防止SQL注入呢?

解决

这里提供两种解决方案。

方案一:对传入参数进行编码转义。

方案二:使用Python MySQLdb模块自带的安全方法。

第一种方案在许多PHP防注入实践中均有体现,即对特殊字符进行转义或过滤处理。

第二种方案则是利用内部安全方法,类似于PHP中的PDO机制。只需对前述数据库类进行简单修改即可实现。

修改后的代码如下:

class Database:
 aurl = '127.0.0.1'
 user = 'root'
 password = 'root'
 db = 'testdb'
 charset = 'utf8'

 def __init__(self):
  self.connection = MySQLdb.connect(self.aurl, self.user, self.password, self.db, charset=self.charset)
  self.cursor = self.connection.cursor()

 def insert(self, query, params):
  try:
   self.cursor.execute(query, params)
   self.connection.commit()
  except Exception, e:
   print e
   self.connection.rollback()

 def query(self, query, params):
  cursor = self.connection.cursor(MySQLdb.cursors.DictCursor)
  cursor.execute(query, params)
  return cursor.fetchall()

 def __del__(self):
  self.connection.close()

在调用execute执行时,需传入两个参数:第一个是参数化的SQL语句,第二个是对应的实际参数值。函数内部会对传入的参数值进行相应处理以防范SQL注入。实际使用方法如下:

preUpdateSql = "UPDATE `article` SET title=%s,date=%s,mainbody=%s WHERE id=%s"
mysql.insert(preUpdateSql, [title, date, content, aid])

通过这种方式即可有效防止SQL注入。当传入一个列表后,MySQLdb模块内部会将其序列化为元组,并执行escape操作以确保安全。

总结

我将逐步修正过往脚本中存在SQL注入漏洞的代码。以上就是本文的全部内容,希望这些内容能对各位的学习或工作有所帮助。如有任何疑问,欢迎留言交流。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。