232

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

私の状況では、ユーザーから入力があります。

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

datamap辞書が必要な場所。私は周りを検索して、eval()これがうまくいく可能性があることを発見しました。データを使用する前に入力の種類を確認できるかもしれないと思ったので、それは実行可能なセキュリティ対策になるでしょう。

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

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

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

4

7 に答える 7

245

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

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

ast.literal_eval必要なときにいつでも使用できますeval。通常、文字通りの Python ステートメントを評価するべきではありません。

于 2013-03-04T08:52:53.967 に答える
135

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

提供される文字列またはノードは、次の Python リテラル構造のみで構成されている場合があります: 文字列、バイト、数値、タプル、リスト、辞書、セット、ブール値、およびNone.

に渡すとエラーが発生しますが__import__('os').system('rm -rf /a-path-you-really-care-about')、ファイルは喜んで削除されます。ast.literal_eval()eval()

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

于 2013-03-04T08:54:35.553 に答える
70

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 accept operators in string format
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.__name__ == n
    ][0]
):
fc("function")(
    fc("code")(
        0,0,0,0,"KABOOM",(),(),(),"","",0,""
    ),{}
)()
)()
"""
eval(s, {'__builtins__':{}})

上記のコードでは().__class__.__bases__[0]、オブジェクト自体だけです。ここで、すべてのサブクラスをインスタンス化しました。ここでの主な目的は、そこからnenter code hereという名前のクラスを 1 つ見つけることです。

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

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

于 2016-01-20T15:56:33.030 に答える
47

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

を使用しast.literal_evalます。


例として、プロンプトでこれを入力すると、非常に悪い場合があります。

__import__('os').system('rm -rf /a-path-you-really-care-about')
于 2013-03-04T08:52:44.353 に答える
6

必要なのはユーザー提供の辞書だけである場合、より良い解決策はjson.loadsです。主な制限は、json dicts が文字列キーを必要とすることです。また、リテラル データしか提供できませんが、これはliteral_eval.

于 2017-08-02T16:42:15.263 に答える