web-dev-qa-db-ja.com

pythonのeval()とast.literal_eval()を使用していますか?

eval()が可能な解決策として出てきたコードがある状況があります。今までeval()を使用する必要はありませんでしたが、それが引き起こす可能性のある潜在的な危険性に関する多くの情報に出会いました。そうは言っても、私はそれを使うことについて非常に警戒しています。

私の状況は、ユーザーからの入力があることです。

datamap = raw_input('Provide some data here: ')

datamapは辞書である必要があります。私は周りを検索し、eval()がこれを解決できることを発見しました。データを使用する前に入力のタイプを確認できる可能性があると考えましたが、これは実行可能なセキュリティ予防策になります。

datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
    return

私はドキュメントを読んで、これが安全かどうかはまだわかりません。 evalは、データが入力されるとすぐに、またはdatamap変数が呼び出された後にデータを評価しますか?

astモジュールの.literal_eval()が唯一の安全なオプションですか?

138
tijko

datamap = eval(raw_input('Provide some data here: '))は、実際にコードを評価することを意味しますbefore安全でないかどうかを判断します。関数が呼び出されるとすぐにコードを評価します。 evalの危険性 も参照してください。

ast.literal_evalは、入力が有効なPythonデータ型でない場合に例外を発生させるため、そうでない場合、コードは実行されません。

evalが必要なときはいつでもast.literal_evalを使用してください。通常、リテラルPythonステートメントを評価するべきではありません。

155
Volatility

ast.literal_eval()は、Pythonの構文の小さなサブセットのみが有効であると見なします。

提供される文字列またはノードは、次のPythonリテラル構造のみで構成されます:文字列、数値、タプル、リスト、辞書、ブール値、なし。

__import__('os').system('rm -rf /a-path-you-really-care-about')ast.literal_eval()に渡すとエラーが発生しますが、eval()はドライブを正常に消去します。

ユーザーに単純な辞書のみを入力させているように見えるので、ast.literal_eval()を使用します。それはあなたが望むことを安全に行い、それ以上は何もしません。

88
Blender

Pythonのeagerの評価では、eval(raw_input(...))は、後でデータをどう処理するかに関係なく、evalにヒットするとすぐにユーザーの入力を評価します。したがって、これは安全ではありません、特にevalユーザー入力の場合。

ast.literal_evalを使用します。


例として、プロンプトでこれを入力することは非常に非常に悪いでしょう:

__import__('os').system('rm -rf /a-path-you-really-care-about')
40
nneonneo

eval:これは非常に強力ですが、信頼できない入力から評価する文字列を受け入れる場合にも非常に危険です。評価される文字列が "os.system( 'rm -rf /')"であるとしますか?コンピューター上のすべてのファイルの削除が実際に開始されます。

ast.literal_eval:式ノードまたはPythonリテラルまたはコンテナ表示を含む文字列を安全に評価します。提供される文字列またはノードは、次のPythonリテラル構造のみで構成されます:文字列、バイト、数値、タプル、リスト、辞書、セット、ブール値、なし、バイトおよびセット。

構文:

eval(expression, globals=None, locals=None)
import ast
ast.literal_eval(node_or_string)

例:

# python 2.x - doesn't accepts operators in the string 
import ast
ast.literal_eval('[1, 2, 3]')  # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string


# python 3.0 -3.6
import ast
ast.literal_eval("1+1") # output : 2
ast.literal_eval("{'a': 2, 'b': 3, 3:'xyz'}") # output : {'a': 2, 'b': 3, 3:'xyz'}
# type dictionary
ast.literal_eval("",{}) # output : Syntax Error required only one parameter
ast.literal_eval("__import__('os').system('rm -rf /')") # output : error

eval("__import__('os').system('rm -rf /')") 
# output : start deleting all the files on your computer.
# restricting using global and local variables
eval("__import__('os').system('rm -rf /')",{'__builtins__':{}},{})
# output : Error due to blocked imports by passing  '__builtins__':{} in global

# But still eval is not safe. we can access and break the code as given below
s = """
(lambda fc=(
lambda n: [
    c for c in 
        ().__class__.__bases__[0].__subclasses__() 
        if c.__== n
    ][0]
):
fc("function")(
    fc("code")(
        0,0,0,0,"KABOOM",(),(),(),"","",0,""
    ),{}
)()
)()
"""
eval(s, {'__builtins__':{}})

上記のコードでは().__class__.__bases__[0]はオブジェクトそのものにすぎません。ここで、すべてのサブクラスのインスタンスを作成しました。ここでの主なenter code hereobjectiveは、nそれから。

インスタンス化されたサブクラスからcodeオブジェクトとfunctionオブジェクトを作成する必要があります。これは、オブジェクトのサブクラスにアクセスしてシステムをアタッチするCPythonの代替方法です。

python 3.7よりast.literal_eval()はより厳密になりました。任意の数の加算と減算は許可されなくなりました。 リンク

35

ユーザーが提供する辞書のみが必要な場合、より良い解決策はjson.loadsです。主な制限は、json dictが文字列キーを必要とすることです。また、リテラルデータのみを提供できますが、literal_evalの場合も同様です。

3
Chinasaur

私はast.literal_eval()で立ち往生しました。 IntelliJ IDEAデバッガーで試してみましたが、デバッガー出力でNoneを返し続けました。

しかし、後でその出力を変数に割り当て、コードで出力しました。うまくいきました。共有コードの例:

import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)

そのpythonバージョン3.6。

1
M Haziq