Flask-sqlalchemy + pymssql阻止来自存储过程参数的SQL注入

时间:2017-11-07 18:23:13

标签: python flask sqlalchemy sql-injection pymssql

我的下一条路线完美无缺:

@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'])

问题是由于param,它可能容易受到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,但我得到了同样的错误。

1 个答案:

答案 0 :(得分:0)

使用占位符的一个好处是您不需要 - 也不应该 - 手动引用。所以当你加入

""" ... N':id' ... """
在您的查询中

可能呈现为

""" ... N''179'' ... """

或类似的,取决于你的参数的类型等。然后修复删除引号,让SQLAlchemy / 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()构造提供的后端中立的SQLAlchemy抽象。 Session.execute()隐式包装你的文本SQL,如果你省略了它。 %s?等是DP-API特定的占位符样式。 pymssql似乎使用百分比样式。