繁体   English   中英

如何在原始查询中将Oracle列安全地绑定到ORDER BY到SQLAlchemy?

[英]How to safely bind Oracle column to ORDER BY to SQLAlchemy in a raw query?

我正在尝试执行原始sql查询,并根据用户输入安全地通过/ asc / desc传递命令。 这是分页数据网格的后端。 我一生无法解决如何安全地执行此操作。 参数将转换为字符串,因此Oracle无法执行查询。 我在互联网上的任何地方都找不到任何示例。 安全完成此任务的最佳方法是什么? (我没有使用ORM,必须是原始sql)。

我的解决方法是将ASC / DESC设置为我设置的变量。 这工作正常并且安全。 但是,如何将列名绑定到ORDER BY? 那有可能吗? 我可以将一堆列列入白名单,并像使用ASC / DESC一样执行类似的操作。 我只是好奇是否有办法绑定它。 谢谢。

@default.route('/api/barcodes/<sort_by>/<sort_dir>', methods=['GET'])
@json_enc
def fetch_barcodes(sort_by, sort_dir):
    #time.sleep(5)

    # Can't use sort_dir as a parameter, so assign to variable to sanitize it
    ord_dir = "DESC" if sort_dir.lower() == 'desc' else 'ASC'

    records = []
    stmt = text("SELECT bb_request_id,bb_barcode,bs_status, "
        "TO_CHAR(bb_rec_cre_date, 'MM/DD/YYYY') AS bb_rec_cre_date "
        "FROM bars_barcodes,bars_status "
        "WHERE bs_status_id = bb_status_id "
        "ORDER BY :ord_by :ord_dir ")
    stmt = stmt.bindparams(ord_by=sort_by,ord_dir=ord_dir)
    rs = db.session.execute(stmt)
    records = [dict(zip(rs.keys(), row)) for row in rs]

DatabaseError:(cx_Oracle.DatabaseError)ORA-01036:非法变量名称/编号[SQL:“ SELECT bb_request_id,bb_barcode,bs_status,TO_CHAR(bb_rec_cre_date,'MM / DD / YYYY')AS bb_rec_cre_date FROM bar_barcodes,bars_status DER_ID BY:ord_by:ord_dir“] [参数:{'ord_by':u'bb_rec_cre_date','ord_dir':'ASC'}]

基于可接受答案的更新解决方案:

def fetch_barcodes(sort_by, sort_dir, page, rows_per_page):
    ord_dir_func = desc if sort_dir.lower() == 'desc' else asc
    query_limit = int(rows_per_page)
    query_offset = (int(page) - 1) * query_limit

    stmt = select([column('bb_request_id'),
                   column('bb_barcode'),
                   column('bs_status'),
                   func.to_char(column('bb_rec_cre_date'), 'MM/DD/YYYY').label('bb_rec_cre_date')]).\
        select_from(table('bars_barcode')).\
        select_from(table('bars_status')).\
        where(column('bs_status_id') == column('bb_status_id')).\
        order_by(ord_dir_func(column(sort_by))).\
        limit(query_limit).offset(query_offset)

    result = db.session.execute(stmt)
    records = [dict(row) for row in result]
    response = json_return()
    response.addRecords(records)
    #response.setTotal(len(records))
    response.setTotal(1001)
    response.setSuccess(True)
    response.addMessage("Records retrieved successfully. Limit: " + str(query_limit) + ", Offset: " + str(query_offset) + " SQL: " + str(stmt))

    return response

您可以为此使用诸如table()column()类的Core构造,而不是原始SQL字符串。 这样可以使您的生活更轻松:

from sqlalchemy import select, table, column, asc, desc

ord_dir = desc if sort_dir.lower() == 'desc' else asc

stmt = select([column('bb_request_id'),
               column('bb_barcode'),
               column('bs_status'),
               func.to_char(column('bb_rec_cre_date'),
                            'MM/DD/YYYY').label('bb_rec_cre_date')]).\
    select_from(table('bars_barcodes')).\
    select_from(table('bars_status')).\
    where(column('bs_status_id') == column('bb_status_id')).\
    order_by(ord_dir(column(sort_by)))

table()column()表示带有Column的完整Table对象的句法部分,可以按这种方式用于转义目的:

假定由column()处理的文本与数据库列的名称一样进行处理; 如果字符串包含大小写混合,特殊字符或与目标后端上的已知保留字匹配,则该列表达式将使用后端确定的引用行为来呈现。

不过,将白名单列入可能不是一个坏主意。

请注意,您无需手动zip()行代理即可生成字典。 它们按原样充当映射,如果出于序列化等原因需要dict() ,则只需执行dict(row)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM