pandas 在将字符串传递给panda.eval之前对其进行格式化有什么风险?

vaqhlq81  于 2022-11-05  发布在  其他
关注(0)|答案(1)|浏览(174)

pandas.DataFrame.query获取表示 Dataframe 操作的人类可读字符串,然后使用pandas.eval对它们进行求值(在此记录)。如this question中所述,我想写下面这样的函数,它们编译查询字符串的方式不会产生flake8错误。d是“一个非常滑的斜坡”,但我不知道为什么。
以这种方式设置查询字符串的格式有什么问题?

import pandas as pd

def query_column_equality(df, a, b):
    if a in df.columns:
        return df.query('{} == @q'.format(a), local_dict={'q': b})
    else:
        raise KeyError(a)

def query_column_isin(df, a, b):
    if a in df.columns:
        return df.query('{}.isin(@q)'.format(a), local_dict={'q': b})
    else:
        raise KeyError(a)

df = pd.DataFrame({'a': [1, 2], 'b': [10, 20]})

query_value = 20
print(query_column_equality(df, 'b', query_value))

query_iterable = [20]
print(query_column_isin(df, 'b', query_iterable))
8zzbczxx

8zzbczxx1#

有人告诉我,格式化即将被求值的字符串是“一个极其危险的斜坡”,但我不知道为什么。
我认为这是一个很好的建议。我认为有些问题只能用eval()来解决,但是99%的使用eval()的代码可以用其他方法来更容易、更安全地解决。
我会把这个算在99%里。
例如,这两种方法都可以以更安全的方式重写:

return df.query('{} == @q'.format(a), local_dict={'q': b})
...
return df.query('{}.isin(@q)'.format(a), local_dict={'q': b})

可变为:

return df.loc[df[a] == b]
...
return df.loc[df[a].isin(b)]

我的问题是这里的代码是否有风险--对列的检查是否足以安全地运行查询?
不,我不这么认为。想象一下,你在程序的某个地方使用read_csv加载了一个不可信的CSV。CSV可以合法地包含列import os; os.system('rm -rf *')。如果你检查你正在查询的列是否确实存在于 Dataframe 中,那么检查就会成功。
有很多方法可以阻止这种情况,防止任何漏洞。但最终它们并不像使用不容易被注入的替代方法那么简单。

相关问题