Güvenli olmayan kodun yanlışlıkla kullanılmadığından emin olun


10

Bir işlev f(), programımı çalıştıran makinede eval()oluşturduğum ve sakladığım verilerle (veya tehlikeli bir şeyle) kullanır local_file:

import local_file

def f(str_to_eval):
    # code....
    # .... 
    eval(str_to_eval)    
    # ....
    # ....    
    return None


a = f(local_file.some_str)

f() ona sağladığım dizeler benim olduğu için çalıştırmak güvenlidir.

Ancak, güvenli olmayan bir şey (örneğin kullanıcı girişi) için kullanmaya karar verirsem işler çok yanlış gidebilir . Ayrıca, local_fileyerel olarak durursa, bu dosyayı da sağlayan makineye güvenmem gerektiğinden bir güvenlik açığı oluşturur.

Bu işlevin kullanımının güvenli olmadığını (belirli ölçütler karşılanmadığı sürece) asla "unutmamamı" nasıl sağlarım?

Not: eval()tehlikelidir ve genellikle güvenli bir şeyle değiştirilebilir.


1
Genellikle "bunu yapmamalısın" demek yerine sorulan sorularla birlikte gitmek isterim, ancak bu durumda bir istisna yapacağım. Eval kullanmanız için hiçbir neden olmadığından eminim. Bu işlevler, yorumlanmış dillerle ne kadar yapılabileceğini bir tür kavram kanıtı olarak PHP ve Python gibi dillerde içerir. Kod oluşturan bir kod yazabilmeniz, ancak aynı mantığı bir işleve kodlayamamanız temelde düşünülemez. Python muhtemelen ihtiyacınız olanı yapmanıza izin verecek geri aramalar ve fonksiyon bağlamaları vardır
user1122069

1
" Bu dosyayı sağlayan makineye de güvenmem gerekecek " - her zaman kodunuzu yürüttüğünüz makineye güvenmeniz gerekir.
Bergi

Dosyaya "Bu dize değerlendirilir; lütfen buraya kötü amaçlı kod koymayın" ifadesini ekleyin.
user253751

@immibis Bir yorum yeterli olmaz. Tabii ki büyük bir "UYARI: Bu işlev işlevin belgelerinde eval ()" kullanır, ama ben bundan çok daha güvenli bir şey güveniyor. Örneğin (sınırlı bir süre nedeniyle) her zaman bir işlevin belgelerini tekrar okumam. Ben de olmam gerektiğini düşünüyorum. Bir şeylerin güvensiz olduğunu bilmenin daha hızlı (yani daha verimli) yolları vardır, örneğin Murphy'nin cevabında bağladığı yöntemler gibi .
Fermi paradoksu

@Fermiparadox, değerlendirmeyi sorudan çıkardığınızda yararlı bir örnek olmadan olur. Şimdi, SQL parametrelerinden kaçmamak gibi kasıtlı gözetim nedeniyle güvenli olmayan bir işlevden mi bahsediyorsunuz? Test kodunun bir üretim ortamı için güvenli olmadığı anlamına mı geliyor? Her neyse, şimdi Amon'un cevabı hakkındaki yorumunuzu okudum - temel olarak işlevinizi nasıl güvenceye alacağınızı düşünüyordunuz.
user1122069

Yanıtlar:


26

“Güvenli” girdileri dekore etmek için bir tür tanımlayın. İşlevinizde f(), bağımsız değişkenin bu türde olduğunu iddia edin veya bir hata atın. Hiçbir zaman kısayol tanımlamayacak kadar akıllı olun def g(x): return f(SafeInput(x)).

Misal:

class SafeInput(object):
  def __init__(self, value):
    self._value = value

  def value(self):
    return self._value

def f(safe_string_to_eval):
  assert type(safe_string_to_eval) is SafeInput, "safe_string_to_eval must have type SafeInput, but was {}".format(type(safe_string_to_eval))
  ...
  eval(safe_string_to_eval.value())
  ...

a = f(SafeInput(local_file.some_str))

Bu kolayca atlatılabilirken, kazara bunu zorlaştırır. İnsanlar böyle bir acımasız tip kontrolü eleştirebilirler, ama konuyu kaçırırlardı. Yana SafeInputtip bir veri türü olup tip kimlik denetimi, sınıflandırma edilebilir bir nesne merkezli sınıf olan type(x) is SafeInputtip uyumluluğunu kontrol daha güvenlidir isinstance(x, SafeInput). Belirli bir türü zorlamak istediğimiz için, açık türü görmezden gelmek ve sadece örtülü ördek yazımı yapmak da burada tatmin edici değildir. Python'un bir tür sistemi var, bu yüzden olası hataları yakalamak için kullanalım!


5
Yine de küçük bir değişiklik gerekebilir. assertoptimize edilmiş python kodunu kullanacağım için otomatik olarak kaldırılır. Böyle bir if ... : raise NotSafeInputErrorşeye ihtiyaç duyulacaktı.
Fermi paradoksu

4
Yine de bu yolda gidiyor, açık bir tür denetimi gerekmez böylece bir yönteme taşımak şiddetle tavsiye ediyorum . Yönteme, diğer sınıflarınızın hiçbirinde kullanılmayan bir ad verin. Bu şekilde, test amacıyla her şeyi alay edebilirsiniz. eval()SafeInput
Kevin

@Kevin: evalYerel değişkenlere erişimi olduğu için, kodun değişkenleri nasıl değiştirdiğine bağlı olabilir. Değerlendirmeyi başka bir yönteme taşıyarak, artık yerel değişkenleri değiştirme yeteneğine sahip olmayacaktır.
Sjoerd Job Postmus

Diğer bir adım, kurucuya SafeInputyerel dosyanın adını / tanıtıcısını alıp okumayı kendisi yapmak ve verilerin gerçekten yerel bir dosyadan gelmesini sağlamak olabilir.
Owen

1
Python ile fazla deneyimim yok, ama bir istisna atmak daha iyi değil mi? Çoğu dilde varsayımlar kapatılabilir ve (anladığım kadarıyla) hata ayıklama için güvenlikten daha fazladır. İstisnalar ve konsoldan çıkılması, bir sonraki kodun çalıştırılmayacağını garanti eder.
user1122069

11

Joel'in bir kez işaret ettiği gibi, yanlış kodun yanlış görünmesini sağlayın ("Gerçek Çözüm" bölümüne ilerleyin veya daha iyisi tamamen okuyun; işlev adları yerine değişkene değerse bile buna değer). Bu yüzden alçakgönüllü bir şekilde işlevinizi yeniden adlandırmanızı öneririm f_unsafe_for_external_use()- büyük olasılıkla kendiniz için bir kısaltma şeması bulacaksınız.

Düzenleme: Amon'un önerisi aynı tema üzerinde çok iyi, OO tabanlı bir varyasyon olduğunu düşünüyorum :-)


0

Öneriyi @ amon ile tamamlayarak, burada strateji modelini ve yöntem nesnesi desenini birleştirmeyi de düşünebilirsiniz.

class AbstractFoobarizer(object):
    def handle_cond(self, foo, bar):
        """
        Handle the event or something.
        """
        raise NotImplementedError

    def run(self):
        # do some magic
        pass

Ve sonra 'normal' bir uygulama

class PrintingFoobarizer(AbstractFoobarizer):
    def handle_cond(self, foo, bar):
        print("Something went very well regarding {} and {}".format(foo, bar))

Ve bir yönetici-girdi-değerlendirme uygulaması

class AdminControllableFoobarizer(AbstractFoobarizer):
    def handle_cond(self, foo, bar):
        # Look up code in database/config file/...
        code = get_code_from_settings()
        eval(code)

(Not: gerçek dünya ish örneği ile daha iyi bir örnek verebilirim).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.