2

私は、動作するためにファイルパーサーをロードする必要があるメインのPythonモジュールを作成しました。最初は、テキストパーサーモジュールが1つだけでしたが、さまざまなケースに合わせてパーサーを追加する必要があります。
parser_class1.py
parser_class2.py
parser_class3.py

実行中のインスタンスごとに必要なのは1つだけなので、コマンドラインでロードすることを考えています。

mmain.py -p parser_class1

この目的で、メインモジュールが呼び出されるときにロードするパーサーを選択するためにこのコードを作成しました。

#!/usr/bin/env python

import argparse
aparser = argparse.ArgumentParser()
aparser.add_argument('-p',
            action='store',
            dest='module',
            help='-p module to import')
results = aparser.parse_args()

if not results.module:
    aparser.error('Error! no module')
try:
    exec("import %s" %(results.module))
    print '%s imported done!'%(results.module)
except ImportError, e:
    print e

しかし、私はこの方法は危険であり、おそらくスターダードではないことを読んでいました。

では、このアプローチは大丈夫ですか?または私はそれを行う別の方法を見つけなければなりませんか?なんで?ありがとう、どんなコメントでも大歓迎です。

4

3 に答える 3

5

実際にはimport、条件付きブロック内でステートメントを実行するだけで済みます。

if x:
    import module1a as module1
else:
    import module1b as module1

これを使用して、さまざまなホワイトリストに登録されたモジュールのインポートをさまざまな方法で説明できますが、効果的には、インポートを事前にプログラムしてから、基本的にGOTOを使用して適切なインポートを行うことです...ユーザーにインポートを許可するだけの場合任意の引数の場合、__import__関数は。ではなく、進むべき道になりevalます。

アップデート:

コメントで@thedoxが言及したように、このas module1セクションは、異なる基になるコードで同様のAPIをロードするための慣用的な方法です。まったく異なるAPIを使用してまったく異なることを行う場合、それは従うべきパターンではありません。この場合のより合理的なパターンは、特定のインポートに関連するコードをそのインポートステートメントに含めることです。

if ...:
    import module1
    # do some stuff with module1 ...

else:
    import module2
    # do some stuff with module2 ...

セキュリティに関しては、ユーザーが任意のコードセット(たとえば、独自のモジュールなど)のインポートを許可する場合、ユーザー入力で使用する場合と大差ありませんeval。これは本質的に同じ脆弱性です。ユーザーはプログラムに独自のコードを実行させることができます。

ユーザーに任意のモジュールをインポートさせる本当に安全な方法はまったくないと思います。ここでの例外は、ファイルシステムにアクセスできないため、インポートする新しいコードを作成できない場合です。この場合、基本的にホワイトリストのケースに戻り、将来を防ぐために明示的なホワイトリストを実装することもできます。将来のある時点でユーザーがファイルシステムにアクセスした場合の脆弱性。

于 2013-03-25T18:50:13.520 に答える
1

使い方はこちら__import__()

allowed_modules = ['os', 're', 'your_module', 'parser_class1.py', 'parser_class2.py']

if not results.module:
    aparser.error('Error! no module')
try:
    if results.module in allowed_modules:
        module = __import__(results.module)
        print '%s imported as "module"'%(results.module)
    else:
        print 'hey what are you trying to do?'
except ImportError, e:
    print e

module.your_function(your_data)

EVALvs__IMPORT__()

を使用evalすると、ユーザーはコンピューター上で任意のコードを実行できます。そうしないでください。__import__()ユーザーがモジュールをロードすることのみを許可し、明らかにユーザーが任意のコードを実行することを許可しません。しかし、それは明らかに安全なだけです。

提案された機能は、allowed_modulesロード時に悪意のあるコードが実行されている可能性のある任意のモデルをロードできるため、リスクがあります。攻撃者がファイルをどこかにロードし(共有フォルダー、ftpフォルダー、Webサーバーによって管理されるアップロードフォルダーなど)、引数を使用して呼び出す可能性があります。

ホワイトリスト

を使用allowed_modulesすると問題は軽減されますが、完全には解決されません。さらに強化するには、攻撃者が「os.py」、「re.py」、「your_module.py」、「parser_class1.py」をユーザーに書き込んだかどうかを確認する必要があります。スクリプトフォルダ。Pythonが最初にモジュールを検索するため(docs)。

最終的には、sha1sumのように、 parser_class *.pyコードをハッシュのリストと比較できます。

最後の注意:実際には、ユーザーがスクリプトフォルダーへの書き込みアクセス権を持っている場合、絶対に安全なコードを保証することはできません。

于 2013-03-25T18:57:16.003 に答える
0

その解析関数用にインポートできる可能性のあるすべてのモジュールを検討してから、caseステートメントまたはディクショナリを使用して正しいモジュールをロードする必要があります。例えば:

import parser_class1, parser_class2, parser_class3

parser_map = {
    'class1': parser_class1,
    'class2': parser_class2,
    'class3': parser_class3,
}

if not args.module:
    #report error
    parser = None
else:
    parser = parser_map[args.module]
#perform work with parser

この例のparser_classNモジュールのいずれかをロードするのにコストがかかる場合は、そのモジュールを返すラムダまたは関数を定義して(つまりdef get_class1(): import parser_class1; return parser_class1)、行を次のように変更できます。parser = parser_map[args.module]()

exec検証されていないユーザー入力を実行しているため、このオプションは非常に危険です。ユーザーが次のようなことをしたと想像してみてください-

mmain.py -p "parser_class1; some_function_or_code_that_is_malicious()"
于 2013-03-25T18:56:34.423 に答える