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()
が唯一の安全なオプションですか?
datamap = eval(raw_input('Provide some data here: '))
は、実際にコードを評価することを意味しますbefore安全でないかどうかを判断します。関数が呼び出されるとすぐにコードを評価します。 eval
の危険性 も参照してください。
ast.literal_eval
は、入力が有効なPythonデータ型でない場合に例外を発生させるため、そうでない場合、コードは実行されません。
eval
が必要なときはいつでもast.literal_eval
を使用してください。通常、リテラルPythonステートメントを評価するべきではありません。
ast.literal_eval()
は、Pythonの構文の小さなサブセットのみが有効であると見なします。
提供される文字列またはノードは、次のPythonリテラル構造のみで構成されます:文字列、数値、タプル、リスト、辞書、ブール値、なし。
__import__('os').system('rm -rf /a-path-you-really-care-about')
をast.literal_eval()
に渡すとエラーが発生しますが、eval()
はドライブを正常に消去します。
ユーザーに単純な辞書のみを入力させているように見えるので、ast.literal_eval()
を使用します。それはあなたが望むことを安全に行い、それ以上は何もしません。
Pythonのeagerの評価では、eval(raw_input(...))
は、後でデータをどう処理するかに関係なく、eval
にヒットするとすぐにユーザーの入力を評価します。したがって、これは安全ではありません、特にeval
ユーザー入力の場合。
ast.literal_eval
を使用します。
例として、プロンプトでこれを入力することは非常に非常に悪いでしょう:
__import__('os').system('rm -rf /a-path-you-really-care-about')
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 here
objectiveは、nそれから。
インスタンス化されたサブクラスからcode
オブジェクトとfunction
オブジェクトを作成する必要があります。これは、オブジェクトのサブクラスにアクセスしてシステムをアタッチするCPython
の代替方法です。
python 3.7よりast.literal_eval()はより厳密になりました。任意の数の加算と減算は許可されなくなりました。 リンク
ユーザーが提供する辞書のみが必要な場合、より良い解決策はjson.loads
です。主な制限は、json dictが文字列キーを必要とすることです。また、リテラルデータのみを提供できますが、literal_eval
の場合も同様です。
私は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。