解决 SQL 注入问题,在于不去拼接字符串构造 SQL,而是使用“预编译 + 参数绑定”的方式(即参数化查询)来处理 SQL 请求。抑或是使用ORM。
什么是 SQL 注入?
SQL 注入(SQL Injection)是指攻击者通过构造恶意输入,插入到 SQL 查询语句中,从而操控数据库执行非预期的操作,如绕过登录、删除数据等。
例如:
 | 12
 
 | username = input("请输入用户名:")sql = "SELECT * FROM users WHERE username = '" + username + "';"
 
 | 
当用户输入 admin' OR '1'='1 时,SQL 变成:
| 1
 | SELECT * FROM users WHERE username = 'admin' OR '1'='1';
 | 
这会导致永远为真,绕过认证。
 解决方案1:预编译+参数绑定(Prepared Statements)
将 SQL 语句结构提前固定好,只在后续绑定参数,而不是拼接字符串,数据库系统会提前“准备”好 SQL 的执行计划。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | import psycopg2
 conn = psycopg2.connect(database="testdb", user="postgres", password="yourpassword")
 cursor = conn.cursor()
 
 
 username = input("请输入用户名:")
 
 
 sql = "SELECT * FROM users WHERE username = %s;"
 cursor.execute(sql, (username,))
 
 rows = cursor.fetchall()
 print(rows)
 
 | 
这里的 %s 是占位符,(username,) 是绑定参数。PostgreSQL 会自动对输入内容进行转义和类型处理,用户输入的内容只会当作“数据”,不会被解释为 SQL 代码。
 解决方案2: ORM(Object-Relational Mapping)
ORM 是一种将数据库表映射为程序中的对象 的工具,它允许你用“面向对象的方式”来操作数据库,而不是手写 SQL。
优点包括:
- 代码更简洁、抽象
- 更容易维护和迁移数据库
- 内置 参数化查询机制,天然避免 SQL 注入
一个python+postgresql的简单的例子:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | from sqlalchemy import create_engine, Column, Integer, Stringfrom sqlalchemy.orm import sessionmaker, declarative_base
 
 
 engine = create_engine("postgresql://postgres:yourpassword@localhost/testdb")
 Session = sessionmaker(bind=engine)
 session = Session()
 
 Base = declarative_base()
 
 
 class User(Base):
 __tablename__ = 'users'
 id = Column(Integer, primary_key=True)
 username = Column(String)
 
 
 username_input = input("请输入用户名:")
 user = session.query(User).filter(User.username == username_input).first()
 print(user)
 
 | 
当然,orm实际上更有益于我们进行数据库控制,即增删改查等操作:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 
 | from sqlalchemy import create_engine, Column, Integer, Stringfrom sqlalchemy.orm import sessionmaker, declarative_base
 
 
 engine = create_engine("postgresql://postgres:yourpassword@localhost/testdb")
 Session = sessionmaker(bind=engine)
 session = Session()
 
 
 Base = declarative_base()
 
 
 class User(Base):
 __tablename__ = 'users'
 id = Column(Integer, primary_key=True)
 username = Column(String)
 email = Column(String)
 
 
 Base.metadata.create_all(engine)
 
 
 new_user = User(username="alice", email="alice@example.com")
 session.add(new_user)
 session.commit()
 print(f"插入用户 ID:{new_user.id}")
 
 
 
 print("所有用户:")
 users = session.query(User).all()
 for user in users:
 print(user.id, user.username, user.email)
 
 
 user = session.query(User).filter(User.username == "alice").first()
 if user:
 print("找到用户:", user.username, user.email)
 
 
 if user:
 user.email = "alice_updated@example.com"
 session.commit()
 print("已更新用户邮箱:", user.email)
 
 
 if user:
 session.delete(user)
 session.commit()
 print("已删除用户:", user.username)
 
 
 session.close()
 
 |