Python Discord Bot使用SQLite的SQL注入原理与防范方法
Discord Bot 场景下的SQL注入原理与防范方案
先澄清几个常见的认知误区
- 不存在“SQLite本身就容易引发SQL注入”的问题,所有SQL注入的风险来源永远是手写拼接SQL字符串的开发习惯,不管你用SQLite、MySQL还是其他数据库,只要把外部可控的内容直接拼进SQL执行语句里,就必然存在注入风险。
- 别人推荐的aiosql本质是异步SQL操作封装库,它本身不会自动防御注入,能从根源防注入的核心是参数化查询。哪怕你用原生sqlite3的异步封装,只要用对参数绑定,安全性和aiosql没有本质区别,完全没必要为了所谓的“安全”强行换技术栈。
SQL注入针对Discord机器人的实际运作逻辑
很多开发者觉得Discord机器人的输入都是经过框架类型校验的,不会有注入风险,实际不然,常见的注入触发路径完全覆盖日常开发场景:
- 利用未做类型校验的无参数化命令
很多开发者写自定义命令时,直接把用户输入的字符串参数拼进SQL。比如用户发送触发命令的内容为!setprefix 1'; DROP TABLE Main;--,只要代码里是用f-string拼接SQL,这段恶意SQL就会被直接执行,轻则删除服务器配置表,重则拖走数据库中所有存储的用户、服务器数据。 - 利用机器人交互组件的输入字段
很多机器人会用弹窗、自定义输入框收集用户提交的欢迎语、自动回复规则,这些场景下的输入如果直接拼进SQL,攻击者完全可以在输入框里塞注入语句,绕过传统的命令参数校验逻辑。 - 看似安全的拼接写法埋下的长期风险
就像你贴的代码里的写法:
这里cursor.execute(f"SELECT welcome_id FROM Main Where guild_id = {ctx.guild.id}")ctx.guild.id是Discord框架返回的固定整数,没有可篡改的空间,现阶段确实不会触发注入,但这种拼接写法是非常坏的开发习惯——只要后续你把同样的拼接逻辑用到用户可控的参数上,立刻就会引入注入风险。
举个可复现的攻击例子:如果后续你加了自定义欢迎语的配置命令,代码写成拼接形式:
那么有配置权限的用户只需要输入# 错误写法,存在极高注入风险 cursor.execute(f"UPDATE Main SET welcome_text = '{user_input}' WHERE guild_id = {ctx.guild.id}")' OR 1=1 --,就可以把数据库里所有服务器的欢迎语全部改成自己设置的内容;如果输入加上; DROP TABLE Main;--,就能直接删空整个数据库表。
可直接落地的防范方案
- 坚决放弃所有f-string、字符串拼接的SQL写法,所有涉及变量传递的SQL语句,100%走参数化绑定
对应你现在的代码,把那行有拼接的SELECT语句改成参数化写法就完全安全:
不管参数是系统生成的整数还是用户输入的字符串,只要走参数绑定,数据库驱动就会自动对内容做转义,从根源上杜绝注入风险,不需要额外写复杂的输入过滤逻辑。# 正确写法,用?做占位符,变量单独放在传递元组里 cursor.execute("SELECT welcome_id FROM Main Where guild_id = ?", (ctx.guild.id,)) - 不要混淆技术选型和安全写法的边界
你完全可以继续用SQLite做Discord机器人的数据库,它的轻量特性非常适合中小规模机器人的本地存储需求,不需要为了“防注入”专门换成aiosql或者重型ORM——哪怕你换了aiosql,只要你还是用字符串拼接写SQL,注入风险一点都不会减少。 - 从权限层面缩小攻击面
所有涉及数据库写操作的命令,严格按照权限判断加装饰器,就像你已经在做的@commands.has_permissions(administrator=True),确保能触发数据库写操作的用户只有服务器管理员,从权限层面把可触发风险的主体控制在最小范围。 - 做好常态化的数据库备份
哪怕做好了所有防护,也要定期把本地的SQLite文件做异地备份,避免极端情况下数据库被篡改、删除导致所有服务器配置丢失。
内容的提问来源于stack exchange,提问作者Ardil Mc
相关产品推荐
相关产品推荐

