Protegendo Eval e Exec no Python

O eval e o exec servem para executar códigos a partir de uma string. Isso é muito poderoso mas ao mesmo tempo muito perigoso, especialmente se você está executando códigos de uma string que veio de um usuário.

Quando usamos o eval, é interessante saber a quais funções, métodos, classes e variáveis podemos acessar dentro desta chamada.

Para descobrir isso podemos executar as seguintes funções, elas irão mostrar quais funções, tipos, variáveis, métodos, classes, estão visíveis naquele exato pedaço de código em que você está mexendo.

[code language="python"] # Mostrando variáveis globais print(globals()) # Mostrando variáveis locais print(locals()) # Mostrando variáveis locais de outra forma print(dir()) [/code]

Para verificar isso dentro do eval, você pode fazer:

[code language="python"] # Mostrando variáveis globais acessíveis dentro do eval print(eval('globals()')) # Mostrando variáveis locais acessíveis dentro do eval print(eval('locals()')) [/code]

Um dos grandes problemas do eval e do exec é poder executar qualquer coisa dentro do módulo __builtins__. Esse módulo é sempre importando quando você chama o eval ou o exec sem informar nenhum parâmetro a mais.

Uma das soluções é simplesmente remover o acesso ao __builtins__:

[code language="python"] eval('123 + 321',{'__builtins__':None}) [/code]

Mas isso traz alguns problemas caso você precise usar algumas funções dele.

Outra solução é pegar o __builtins__ e atribuir None aos módulos mais perigosos:

[code language="python"] def dict_from_module(module): context = {} for setting in dir(module): # you can write your filter here if setting.islower() and setting.isalpha(): context[setting] = getattr(module, setting) return context

constrainted_global_scope = dict_from_module(globals().get('__builtins__')) constrainted_global_scope['classmethod'] = None constrainted_global_scope['compile'] = None constrainted_global_scope['delattr'] = None constrainted_global_scope['eval'] = None constrainted_global_scope['exec'] = None constrainted_global_scope['help'] = None constrainted_global_scope['input'] = None constrainted_global_scope['memoryview'] = None constrainted_global_scope['open'] = None constrainted_global_scope['print'] = None constrainted_global_scope['property'] = None constrainted_global_scope['setattr'] = None constrainted_global_scope['staticmethod'] = None constrainted_global_scope['super'] = None constrainted_global_scope['copyright'] = None constrainted_global_scope['credits'] = None constrainted_global_scope['exit'] = None constrainted_global_scope['quit'] = None constrainted_global_scope['__builtins__'] = None [/code]

E aí, ao chamar o eval, você pode fazer assim:

[code language="python"] eval('342 + 1231',constrainted_global_scope) [/code]

Tome cuidado também com o escopo local, ele também pode abrir brechas para que o usuário altere os valores das suas variáveis. Para impedir isso, você pode simplesmente enviar um dicionário vazio como terceiro parâmetro ou enviar um dicionário com as variáveis que estão permitidas:

[code language="python"] x = 'variavel secreta' # esta ficará escondida do eval y = 123 # esta ficará visível para o eval z = 321 # esta ficará visível para o eval eval('y + z',constrainted_global_scope,{'y': y, 'z': z}) [/code]

Referências

Limitando o que pode ser acessado dentro de um eval https://stackoverflow.com/a/43667259/2789895

Limitando o que pode ser acessado dentro de um eval http://lybniz2.sourceforge.net/safeeval.html

Tutorial de exec no Python https://www.programiz.com/python-programming/methods/built-in/exec

Usando globals() e locals() https://www.dotnetperls.com/globals-python

You should also read:

Fazendo os prints do Python aparecerem no systemctl status

fazer todos os prints passarem o parâmetro flush=True [code language="python"] import functools print = functools.partial(print, flush=True) [/code] https://stackoverflow.com/questions/230751/how-to-flush-output-of-print-function https://fhackts.wordpress.com/2014/11/27/systemd-journal-not-showing-python-3-print/

Menu