Flask-sqlalchemy + pymssql 防止 SQL 从存储过程参数中注入
Flask-sqlalchemy + pymssql prevent SQL injections from Stored Procedure params
我有下一条完美运行的路线:
@home_app.route('/<id>', methods=['GET', 'POST'])
def home(id):
query = "DECLARE @return_value int, @EXIST bit EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N'" + id +"', @EXIST = @EXIST OUTPUT SELECT @EXIST as N'@EXIST'"
result = db.session.execute(query, bind=db.get_engine(app, 'second_db'))
exist = []
for row in result:
exist.append(row['@EXIST'])
return "Exist? " + str(row['@EXIST'])
问题是它可能容易受到 SQL 注入的攻击。为了解决这个问题,我试过:
query = """
DECLARE @return_value int, @EXIST bit
EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N':id',
@EXIST = @EXIST OUTPUT
SELECT @EXIST as N'@EXIST'
"""
result = db.session.execute(query, {'id': id}, bind=db.get_engine(app, 'second_db'))
但是我得到一个错误:
sqlalchemy.exc.ProgrammingError: (pymssql.ProgrammingError) (102, b"Incorrect syntax near '179'.DB-Lib error message 20018, severity 15:\nGeneral SQL Server error: Check messages from the SQL Server\n") [SQL: "DECLARE @return_value int, @EXIST bit EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N'%(id)s', @EXIST = @EXIST OUTPUT SELECT @EXIST as N'@EXIST'"] [parameters: {'id': '179'}]
我试过其他方法:
query = """
DECLARE @return_value int, @EXIST bit
EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N'%s',
@EXIST = @EXIST OUTPUT
SELECT @EXIST as N'@EXIST'
"""
result = db.session.execute(query, id, bind=db.get_engine(app, 'second_db'))
但是我得到了:
AttributeError: 'list' object has no attribute 'keys'
我也试过
from sqlalchemy.sql import text
query = text(...)
并使用 ?而不是 %s,但我遇到了同样的错误。
使用占位符的好处之一是您不需要——也不应该——手动引用。所以当你包括
""" ... N':id' ... """
在您的查询中可能呈现为
""" ... N''179'' ... """
之类的,具体取决于您的参数类型等。修复方法是删除引号并让 SQLAlchemy/the DB-API 驱动程序处理所有这些:
query = """
DECLARE @return_value int, @EXIST bit
EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = :id,
@EXIST = @EXIST OUTPUT
SELECT @EXIST as N'@EXIST'
"""
result = db.session.execute(
query, {'id': id},
bind=db.get_engine(app, 'second_db'))
命名占位符样式是由 text()
construct. Session.execute()
implicitly wraps your textual SQL, if you've omitted it. %s
, ?
etc. are DP-API specific placeholder styles. pymssql 提供的后端中立 SQLAlchemy 抽象似乎使用百分比样式。
我有下一条完美运行的路线:
@home_app.route('/<id>', methods=['GET', 'POST'])
def home(id):
query = "DECLARE @return_value int, @EXIST bit EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N'" + id +"', @EXIST = @EXIST OUTPUT SELECT @EXIST as N'@EXIST'"
result = db.session.execute(query, bind=db.get_engine(app, 'second_db'))
exist = []
for row in result:
exist.append(row['@EXIST'])
return "Exist? " + str(row['@EXIST'])
问题是它可能容易受到 SQL 注入的攻击。为了解决这个问题,我试过:
query = """
DECLARE @return_value int, @EXIST bit
EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N':id',
@EXIST = @EXIST OUTPUT
SELECT @EXIST as N'@EXIST'
"""
result = db.session.execute(query, {'id': id}, bind=db.get_engine(app, 'second_db'))
但是我得到一个错误:
sqlalchemy.exc.ProgrammingError: (pymssql.ProgrammingError) (102, b"Incorrect syntax near '179'.DB-Lib error message 20018, severity 15:\nGeneral SQL Server error: Check messages from the SQL Server\n") [SQL: "DECLARE @return_value int, @EXIST bit EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N'%(id)s', @EXIST = @EXIST OUTPUT SELECT @EXIST as N'@EXIST'"] [parameters: {'id': '179'}]
我试过其他方法:
query = """
DECLARE @return_value int, @EXIST bit
EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = N'%s',
@EXIST = @EXIST OUTPUT
SELECT @EXIST as N'@EXIST'
"""
result = db.session.execute(query, id, bind=db.get_engine(app, 'second_db'))
但是我得到了:
AttributeError: 'list' object has no attribute 'keys'
我也试过
from sqlalchemy.sql import text
query = text(...)
并使用 ?而不是 %s,但我遇到了同样的错误。
使用占位符的好处之一是您不需要——也不应该——手动引用。所以当你包括
""" ... N':id' ... """
在您的查询中可能呈现为
""" ... N''179'' ... """
之类的,具体取决于您的参数类型等。修复方法是删除引号并让 SQLAlchemy/the DB-API 驱动程序处理所有这些:
query = """
DECLARE @return_value int, @EXIST bit
EXEC @return_value = [dbo].[SP_CHECK_ID] @ID = :id,
@EXIST = @EXIST OUTPUT
SELECT @EXIST as N'@EXIST'
"""
result = db.session.execute(
query, {'id': id},
bind=db.get_engine(app, 'second_db'))
命名占位符样式是由 text()
construct. Session.execute()
implicitly wraps your textual SQL, if you've omitted it. %s
, ?
etc. are DP-API specific placeholder styles. pymssql 提供的后端中立 SQLAlchemy 抽象似乎使用百分比样式。