7

私は、返されたクエリが警告またはアラートになるかどうかを評価するためのカスタム ルールをエンド ユーザーが持つことができるアプリケーションの構築を任されています (独自のしきい値に基づいて)。

ユーザーがロジックをテンプレート化する方法を構築しました。例は次のようになります。

if (abs(<<21>>) >= abs(<<22>>)):
    retVal = <<21>>
else:
    retVal = <<22>>

およびパラメータは<<21>><<22>>プログラムで以前に見つかった値に置き換えられます。execCdこの置換がすべて行われると、変数 ( )に次のように格納された非常に単純な if/else ブロック (この例では) が作成されます。

if (abs(22.0) >= abs(-162.0)):
    retVal = 22.0
else:
    retVal = -162.0

これはexec()正しくなります。さて、これをどう確保するか。私はこの記事を見てきました: http://lybniz2.sourceforge.net/safeeval.html

私のコードは次のようになります。

safe_list = ['math','acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh'] 
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ]) 
safe_dict['abs'] = abs
exec(execCd,{"__builtins__":None},safe_dict)

ただし、この例外で2番目と3番目のパラメーターがある場合、execは失敗します-NameError: name 'retVal' is not defined

エンド ユーザーが持つカスタム ロジックの一部は広範であり、その多くはかなり定期的に変更されます。私はカスタム ロジックを維持したくありません。エンド ユーザーは、さまざまな警告/アラートのしきい値ロジックをすばやくテストできるようにしたいと考えています。

安全でない (意図的または意図的でない) コードからこの exec ステートメントを保護するにはどうすればよいですか?

4

3 に答える 3

7

使用する唯一の安全な方法は、それらを使用しevalないexecことです。

exec を使用する必要はありません。実行する文字列を構築する代わりに、それをオブジェクトに解析し、それを使用してコードの実行を駆動します。

最も単純な方法として、関数を dict に格納し、文字列を使用して呼び出す関数を選択できます。Python 構文を使用している場合、Python はそれ自体を解析するためのすべてのユーティリティを提供しており、それらを使用する必要があります。

于 2012-03-12T18:44:01.087 に答える
5

あなたのexecステートメントは、ローカル環境に retVal を追加するのではなく、safe_dict辞書に追加しています。したがって、そこから元に戻すことができます:

execCd = """
if (abs(22.0) >= abs(-162.0)):
    retVal = 22.0
else:
    retVal = -162.0
"""

safe_list = ['math','acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh'] 
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ]) 
safe_dict['abs'] = abs
exec(execCd,{"__builtins__":None},safe_dict)
retVal = safe_dict["retVal"]
于 2012-03-12T18:47:18.737 に答える
0

これが私の経験からの見方です。exec と eval には主に 2 つの危険があり、どちらにも回避策があることを意味します。

まず、ソース コード内でソース コードを実行します。これは、このコードが次のことを意味します。

eval("mysql_password")

ユーザーは、モジュール全体のすべての変数とインスタンスにアクセスできます。私たちはそれを望んでいません。これが MySQL に接続されたフラスコ サーバーである場合、この方法で eval を実行することは、パスワードを公開するためにドアを公開するようなものです。このユーザーはあなたの MySQL パスワードを取得し、そこにログインするだけでなく、すべてのデータを消去してパスワードを変更することもできました。おめでとう!

代わりに、重要な変数のみをユーザーに提供する辞書を作成する必要があります。それが望ましくない場合は、空の辞書を挿入することもできます。

eval("mysql_password",{},{}) #this will fail as it should in this case.

辞書が 2 つあるのはなぜですか。これは、最初の dict がローカル変数用であり、もう 1 つの dict がグローバル変数用であるためです。これは、文字列内のコードがローカル dict に対して読み書きできるが、グローバル dict からしか読み取れないことを意味します。

それを解決したら、2 番目の問題があります。

ユーザーは、「open()」などのシステム コマンドまたは os などのインポート モジュールを使用して、ディレクトリ内のすべてのファイルを表示し、場合によってはそれらを変更できます。さらに、ビルド済みまたは外部からインストールされたライブラリをインポートして、サーバー全体を制御することもできます。この場合、これに対抗する方法は複数あります。まず、eval は exec よりも安全です。なぜなら、eval は 1 行だけで値を返す必要があるため、ライブラリをインポートして、それを使用して未承認のアクセスを取得することができないからです。次に、できることの 1 つは、スコープ内のすべてのシステム コマンドを上書きすることです。

scope = {"open":None,"file":None,...} #include ALL dangerous system functions, especially "open".

次に、次のように「安全な」評価を行うことができます。

eval("open('wpadmin/sql.ini').read()",scope,scope) # this will now failed since we defined "open" as None in the scope.

残念ながら、完全に防弾にする方法についての保証や完璧な答えはありませんが、問題にアプローチする方法は、限定されたスコープを定義し、eval に固執し、exec を回避するために最善を尽くすことだと思います。exec の問題は、そこで import ステートメントが可能であるため、すべての import ステートメントを削除するフィルターを作成する必要があることです。

3 つ目の方法は (サーバー上で実行する場合)、ftp フォルダー内のすべてのファイルとフォルダーのセキュリティ レベルを微調整して、メイン ソース コード自体がこれらのファイルを読み書きできないようにすることです。そうすれば、ユーザーは「open」などを使用しようとすると「アクセスが拒否されました」というエラーが発生します。

このユースケースで何をするにしても、実行中の PC に大混乱をもたらす可能性のある強力なライブラリは使用しないでください。私は主に、autopy や pyautogui などのライブラリについて考えています。ユーザーがサーバー コンピューター上で突然ナビゲートできるようになり、マウスが勝手に動き回るだけです。それらはアンインストールする必要があります。そうでない場合は、いずれも使用しないでください。

于 2021-08-19T18:47:23.213 に答える