評価:カスタム式を安全に処理する

なぜそれが必要なのですか



さまざまなフィルタリングがいたるところにあります。 たとえば、netfilter(iptables)ファイアウォールには、パッケージを記述するための独自の構文があります。 Apache .htaccessファイルには独自の言語があり、ディレクトリへのアクセスを許可するユーザーと許可しないユーザーを決定する方法があります。 DBMSには、レコードをフィルタリングするための独自の非常に強力な言語(SQL WHERE ...)があります。 電子メールプログラム(サンダーバード、Gmail)-独自のフィルター記述インターフェイス。どの文字がフォルダーに散らばるかに応じて。



そしてどこでも-あなたの自転車。



会計プログラムの場合、ユーザーがより高い給料を受け取る人を選択できるようにすると便利な場合があります(すべての女性、25歳から32歳の男性、または男性の名前がVasyaの場合は50歳まで)。 そして、ユーザー条件の適切な増加(+ 2000ルーブル+前の給与の20%+サービスの各年の1000ルーブル)



オンラインストア(またはその管理パネル)の場合、4〜8 Gbのメモリを搭載したすべてのラップトップを検索します。そのうち3ルーブル以上ありますが、30,000ルーブル未満の場合はAcerまたはAcerさえありません。



もちろん、独自の複雑なフィルターと基準のシステムを追加し、それらのWebインターフェイスを作成できますが、数行ですべてを実行する方が簡単でしょうか?



src="(RAM>=4 and RAM<=8 and stock>3 and not brand=='Acer') or (brand=='Acer' and price<30000)" success, result = evalidate.safeeval(src,notebook)
      
      









私は欲しいと刺す



プログラムにロジックを追加する明白な方法は、 eval()を使用することです。 ソリューションは最も単純で、最も柔軟ですが、大きな落とし穴があります-セキュリティ。 ユーザー式がos.system( 'rm -rf /')を実行するとどうなりますか?



eval()でpythonを「埋める」方法の例:

stackoverflow.com/questions/13066594/is-there-a-way-to-secure-strings-for-pythons-eval

nedbatchelder.com/blog/201206/eval_really_is_dangerous.html(habrの翻訳: habrahabr.ru/post/221937

tav.espians.com/a-challenge-to-break-python-security.html



正しい方法



多くの場合、「正しい方法」をお勧めします。Python自体を使用してテキストフォームのコードをASTツリーに解析し、このツリーを独自に解析して、穀物をヤギから分離します。 しかし、どのように? そしてここで、サイクルマーケティングの主な問題はアリーナに入ります-適切な自転車、または少なくとも良い絵を見つけている間...自転車自体を発明するのは簡単です。



検証する



この目的のための私の小さな自転車evalidateに会ってください 。 誰かがそれを便利だと思うかもしれません(私はそれを十分に柔軟にしようとしました)、そしてソースコードの残りはこの問題を解決する方法の例として役立ちます(もちろん、コードを書くことができない方法)。



ピップを入れます

 pip install evalidate
      
      







簡単な例:



書店のWebサイトにテキスト検索行を配置し(値をsrc変数に渡します-ここでは、Webアプリケーションがブロックされないようにハードコードされていますが、ユーザーの要求からそれらを取得しても安全です)、ユーザーは任意の組み合わせで利用可能な基準で本を検索できます 個別のボタンの代わりに、「利用できない本」、「安い本」、「高価な本」、「第二次世界大戦前に亡くなったオーストラリアまたはオーストラリアに住んでいる著者の本(本) 10部のコピーで、本の100ページあたり1ドル未満の費用がかかります」-1つのテキストボックス。



 import evalidate depot = [ { 'book': 'Sirens of Titan', 'price': 12, 'stock': 4 }, { 'book': 'Gone Girl', 'price': 9.8, 'stock': 0 }, { 'book': 'Choke', 'price': 14, 'stock': 2 }, { 'book': 'Pulp', 'price': 7.45, 'stock': 4 } ] #src='stock==0' # books out of stock src='stock>0 and price>8' # expensive book available for sale for book in depot: success, result = evalidate.safeeval(src,book) if success: if result: print book else: print "ERR:", result
      
      







この場合、srcには「ユーザー」コードがありますが、これは何らかの形で悪い場合があります。 この例では、「良い」コードには2つのオプションがあります。1つ目は在庫のない本を示し、2つ目は入手可能な高価な本を示します。 不正なコード(解析されない、コンテキストにない変数にアクセスできるコード、Call(関数呼び出し)などの未解決の操作を使用するコード)をスリップしようとすると、成功はFalseになり、プログラムはエラーを報告します(しかし、それは落ちず、悪いコードを実行しません)。



別の方法として、ast.parse(またはコードが解析されないか未解決の操作が含まれる場合は例外)で生成されるevalidate.evalidate()でASTツリーを取得し、eval()でコンパイルして実行できます。

 node = evalidate.evalidate(src) code = compile(node,'<usercode>','eval') result = eval(code,{},data)
      
      







さて、モジュールコードを見て(シンプルなので)、自転車を作ります:-)



コミュニティアピール



Evalidateには、デフォルトで独自の「安全な」(?)Python操作のセットが含まれています。 単に、私の個人的な意見では-彼らは安全です。 これは、これらの操作のみを使用してひどいことをする方法が15分間発生しなかったことを意味します。 しかし、それはあなたに来るかもしれませんか? それとも、脆弱性を作成せずに、既定の構成をより柔軟にする(式のより豊富な言語の使用を許可する)リストにいくつかの操作を追加する価値がありますか? アイデアはありますか?



All Articles