Pythonのeval()関数とは?基本的な使い方とセキュリティ対策を解説
Pythonのeval()メソッドは、引数として渡された式(expression)を解析し、プログラム内でその式を実行する関数です。つまり、文字列として記述された内容を、Pythonプログラムの中で実際のコードとして評価・実行できます。実行時に内容が決まる「動的なコード」を実現できる一方で、使い方を誤ると深刻なセキュリティリスクを生むこともあります。本記事では、eval()の基本的な使い方から、安全に利用するための対策までを解説します。
構文
eval()の構文は以下の通りです。
eval(expression, globals=None, locals=None)
各引数の意味は次の通りです。
expression − 評価したいPythonの式を指定します。
globals − 利用可能なグローバルな変数や関数を格納した辞書を指定します(省略可能)。
locals − 利用可能なローカルな変数や関数を格納した辞書を指定します(省略可能)。
使用例:ユーザー入力の式を動的に評価する
次の例では、ユーザーが入力した式をプログラムが受け取り、eval()で評価して結果を表示します。このようにeval()を使うことで、動的なコード実行が可能になります。
# 評価する式をユーザーから入力
user_expr = input("変数aを使った式を入力してください):")
# 変数aの値を入力
a = int(input("aの値を入力してください:"))
# 式を評価
result = eval(user_expr)
# 評価結果を表示
print("Result = {}".format(result))
出力
上記のコードを実行すると、次のような結果が得られます。
変数aを使った式を入力してください):a*(a-3)+a^2 aの値を入力してください:7 Result = 33
eval()のセキュリティリスク
Webアプリケーションやデスクトップアプリのように、外部からの入力を扱うプログラムでeval()を使用すると、セキュリティ上の脆弱性が生じる可能性があります。プログラムを実行するユーザーが、ファイルを削除するシステムコマンドや、機密データをシステム外へ持ち出すような式を入力する恐れがあるためです。
このような脆弱性を防ぐためには、eval()で利用できる関数や変数を制限することが有効です。以下に、代表的な対策を紹介します。
対策1:globalsとlocalsの両方を省略する
両方の引数を省略すると、式は現在のスコープ内でのみ評価され、そのスコープの外にある変数にはアクセスできなくなります。
対策2:globalsに空の辞書を渡す
localsを省略すると、すべての変数がグローバル変数として扱われます。そこで、globalsに空の辞書を渡すと、プログラム内で他のライブラリをインポートしていても、利用できるのは組み込みの変数・関数のみに限定されます。
例
from time import *
print(eval('dir()', {}))
出力
上記のコードを実行すると、次のような結果が得られます。
['__builtins__']
さらに、インポートしたライブラリの中から、特定の関数だけを利用可能にすることもできます。
from time import *
print(eval('dir()', {'sleeptime': sleep, 'Localtime': localtime}))
出力
上記のコードを実行すると、次のような結果が得られます。
['Localtime', '__builtins__', 'sleeptime']
対策3:グローバルとローカルの両方に特定の関数のみを渡す
組み込み関数を一切使えない状態(__builtins__にNoneを指定)にしつつ、ローカル側にはインポートしたライブラリのごく一部の関数だけを許可することも可能です。次の例では、timeライブラリからgmtimeメソッドのみを利用できるようにしています。
例
from time import *
a = 1445945763
print(eval('gmtime(a)', {'__builtins__': None}, {'a': a, 'gmtime': gmtime}))
出力
上記のコードを実行すると、次のような結果が得られます。
time.struct_time(tm_year=2015, tm_mon=10, tm_mday=27, tm_hour=11, tm_min=36, tm_sec=3, tm_wday=1, tm_yday=300, tm_isdst=0)
まとめ
eval()は文字列をコードとして実行できる強力な関数ですが、外部入力をそのまま渡すと任意のコード実行につながる危険があります。利用する場合は、globals・localsを適切に制限し、信頼できない入力に対しては原則としてeval()を使わないことが重要です。
-
Pythonで位置座標の文字列をタプルに変換する方法
文字列として表現された位置座標をタプル形式に変換したい場合、Pythonの組み込み関数である「eval」を使用する方法があります。 eval関数は、引数として渡された式(文字列)を解析し、それをPythonのコードとして実行します。そして、その評価結果を戻り値として返します。この仕組みを利用することで、カンマ区切りの座標文字列を簡単にタプルへ変換できます。 以下に実際の使用例を示します。 サンプルコード my_string = 67.5378, -78.8523 print(The string is : ) print(my_string) my_result = eval(my_str
-
Pythonで式ツリー(式木)を構築する方法:後置記法の式から式木を作るプログラム
式ツリー(Expression Tree)とは、二分木の一種で、葉ノードには演算の対象となる値(オペランド)が格納され、内部ノードには演算子が格納されるデータ構造です。 例:「4 + ((7 + 9) * 2)」という式は、次のような式ツリーで表現できます。 問題を解くためのアプローチ 与えられた式から式ツリーを構築する際には、一般的にスタックというデータ構造を使用します。まず、与えられた後置記法(ポストフィックス記法)の式を走査しながら、以下の手順を実行していきます。 式の中にオペランドが現れた場合は、それをノードとして作成し、スタックにプッシュします。 演算子が現れた場合は、その演算