1.2 SQL操作

1.2.1 【必须】使用参数化查询

  • 使用参数化SQL语句,强制区分数据和命令,避免产生SQL注入漏洞。
  1. # 错误示例
  2. import mysql.connector
  3. mydb = mysql.connector.connect(
  4. ... ...
  5. )
  6. cur = mydb.cursor()
  7. userid = get_id_from_user()
  8. # 使用%直接格式化字符串拼接SQL语句
  9. cur.execute("SELECT `id`, `password` FROM `auth_user` WHERE `id`=%s " % (userid,))
  10. myresult = cur.fetchall()
  1. # 安全示例
  2. import mysql.connector
  3. mydb = mysql.connector.connect(
  4. ... ...
  5. )
  6. cur = mydb.cursor()
  7. userid = get_id_from_user()
  8. # 将元组以参数的形式传入
  9. cur.execute("SELECT `id`, `password` FROM `auth_user` WHERE `id`=%s " , (userid,))
  10. myresult = cur.fetchall()
  • 推荐使用ORM框架来操作数据库,如:使用SQLAlchemy
  1. # 安装sqlalchemy并初始化数据库连接
  2. # pip install sqlalchemy
  3. from sqlalchemy import create_engine
  4. # 初始化数据库连接,修改为你的数据库用户名和密码
  5. engine = create_engine('mysql+mysqlconnector://user:password@host:port/DATABASE')
  1. # 引用数据类型
  2. from sqlalchemy import Column, String, Integer, Float
  3. from sqlalchemy.ext.declarative import declarative_base
  4. Base = declarative_base()
  5. # 定义 Player 对象:
  6. class Player(Base):
  7. # 表的名字:
  8. __tablename__ = 'player'
  9. # 表的结构:
  10. player_id = Column(Integer, primary_key=True, autoincrement=True)
  11. team_id = Column(Integer)
  12. player_name = Column(String(255))
  13. height = Column(Float(3, 2))
  1. # 增删改查
  2. from sqlalchemy.orm import sessionmaker
  3. # 创建 DBSession 类型:
  4. DBSession = sessionmaker(bind=engine)
  5. # 创建 session 对象:
  6. session = DBSession()
  7. # 增:
  8. new_player = Player(team_id=101, player_name="Tom", height=1.98)
  9. session.add(new_player)
  10. # 删:
  11. row = session.query(Player).filter(Player.player_name=="Tom").first()
  12. session.delete(row)
  13. # 改:
  14. row = session.query(Player).filter(Player.player_name=="Tom").first()
  15. row.height = 1.99
  16. # 查:
  17. rows = session.query(Player).filter(Player.height >= 1.88).all()
  18. # 提交即保存到数据库:
  19. session.commit()
  20. # 关闭 session:
  21. session.close()

1.2.2 【必须】对参数进行过滤

  • 将接受到的外部参数动态拼接到SQL语句时,必须对参数进行安全过滤。
  1. def sql_filter(sql, max_length=20):
  2. dirty_stuff = ["\"", "\\", "/", "*", "'", "=", "-", "#", ";", "<", ">", "+",
  3. "&", "$", "(", ")", "%", "@", ","]
  4. for stuff in dirty_stuff:
  5. sql = sql.replace(stuff, "x")
  6. return sql[:max_length]