Assicurarsi che il codice non sicuro non venga usato accidentalmente

10

Una funzione f() utilizza eval() (o qualcosa di pericoloso) con i dati che ho creato e memorizzati in local_file sulla macchina che esegue il mio programma:

import local_file

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


a = f(local_file.some_str)

f() è sicuro da eseguire poiché le stringhe che fornisco sono le mie.

Tuttavia, se decido di usarlo per qualcosa di non sicuro (ad esempio, input dell'utente) le cose potrebbero andare terribilmente sbagliato . Inoltre, se local_file smette di essere locale, creerebbe una vulnerabilità poiché avrei bisogno di fidarmi anche della macchina che fornisce quel file.

Come dovrei assicurarmi di non dimenticare mai che questa funzione non è sicura da usare (a meno che non vengano soddisfatti criteri specifici)?

Nota: eval() è pericoloso e può di solito essere sostituito da qualcosa di sicuro.

    
posta Fermi paradox 03.03.2016 - 21:31
fonte

3 risposte

26

Definisci un tipo per decorare gli input "sicuri". Nella tua funzione f() , asserisci che l'argomento ha questo tipo o genera un errore. Sii abbastanza intelligente per non definire mai una scorciatoia def g(x): return f(SafeInput(x)) .

Esempio:

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))

Mentre questo può essere facilmente aggirato, rende più difficile farlo per sbaglio. Le persone potrebbero criticare un simile tipo di controllo draconiano, ma a loro mancerebbe il punto. Poiché il tipo SafeInput è solo un tipo di dati e non una classe orientata agli oggetti che potrebbe essere sottoclassata, il controllo dell'identità del tipo con type(x) is SafeInput è più sicuro rispetto alla verifica della compatibilità del tipo con isinstance(x, SafeInput) . Dato che vogliamo applicare un tipo specifico, ignorare il tipo esplicito e fare semplicemente una digitazione implicita non è soddisfacente. Python ha un sistema di tipi, quindi usiamolo per cogliere possibili errori!

    
risposta data 03.03.2016 - 21:43
fonte
11

Come Joel ha sottolineato una volta, fa apparire il codice errato in modo sbagliato (scorri verso il basso fino alla sezione "La vera soluzione" , o meglio ancora leggerlo completamente, ne vale la pena, anche se indirizza variabili anziché nomi di funzioni). Quindi suggerisco umilmente di rinominare la tua funzione con qualcosa come f_unsafe_for_external_use() - probabilmente ti verrà in mente qualche schema di abbreviazione.

Modifica: Penso che il suggerimento di amon sia un'ottima variazione basata su OO sullo stesso tema: -)

    
risposta data 03.03.2016 - 21:44
fonte
0

Completando il suggerimento di @amon, puoi anche pensare a combinare il modello strategico qui, così come il modello dell'oggetto metodo.

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

    def run(self):
        # do some magic
        pass

E poi un'implementazione "normale"

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

E un'implementazione di eval-input-admin

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

(Nota: con un esempio di real-world-ish, potrei essere in grado di dare un esempio migliore).

    
risposta data 04.03.2016 - 09:22
fonte

Leggi altre domande sui tag