Adventures in Machine Learning

Safe and Secure Eval() in Python: How to Minimize Security Risks

Python is a popular programming language that has a wide variety of applications, from scientific computing to machine learning. One of the most useful built-in functions of Python is eval(), which allows you to evaluate expressions within your Python code.

This function can be used to evaluate Boolean expressions, mathematical expressions, and general-purpose expressions, making it a versatile tool for both novice and experienced programmers. What is eval()?

At its core, eval() is a Python function that evaluates an expression. This expression can be either a string or a code object, and can contain variables, function calls, and operators.

When eval() is called, Python interprets the expression and returns the result. The first argument of eval() is the expression to be evaluated.

This can be either a string containing the expression or a code object that has been compiled from the expression. For example, you could use eval() to calculate the result of a mathematical expression, such as “2+2”, by passing it as a string to the eval() function.

The second argument of eval() is the globals dictionary. This dictionary contains global variables that are accessible from within the evaluated expression.

This allows you to pass in variables that are defined in your code to the evaluated expression. The third argument of eval() is the locals dictionary.

This dictionary contains local variables that are accessible from within the evaluated expression. This allows you to pass in variables that are defined within the evaluated expression itself.

Boolean Expressions

Boolean expressions are used to evaluate whether a certain condition is true or false. These expressions can include comparison operators such as >, <, ==, and !=, as well as logical operators such as and, or, and not.

For example, you could use eval() to evaluate whether a number is greater than 10 by passing in an expression such as “number > 10”.

Math Expressions

Math expressions are used to perform mathematical calculations, such as addition, subtraction, multiplication, and division. These expressions can also include parentheses to control order of operations.

For example, you could use eval() to calculate the result of a mathematical expression such as “((5+6)*2)-3”.

General-Purpose Expressions

General-purpose expressions can include a variety of operators and functions, and can be used for a wide range of purposes. For example, you could use eval() to concatenate two strings by passing in an expression such as “‘hello’ + ‘world'”.

You could also use eval() to call a function, such as “function_name(argument1, argument2)”. When using eval(), it is important to be aware of the security risks associated with evaluating user input.

Since eval() can evaluate any expression, including expressions provided by users, it can be vulnerable to code injection attacks. To mitigate these risks, it is recommended to only use eval() with trusted expressions that have been thoroughly validated.

In conclusion, Pythons eval() function is a versatile and powerful tool that allows you to evaluate expressions within your Python code. It can be used to evaluate Boolean expressions, mathematical expressions, and general-purpose expressions, making it a valuable resource for developers.

By understanding how eval() works and being cautious about security risks, you can leverage this function to create more efficient and effective Python code. Python’s eval() function is a powerful tool that is often used to evaluate expressions, but it can also pose security risks.

Hackers use techniques such as code injection to exploit the function and compromise security. Fortunately, Python provides several ways to reduce these security concerns.

Restricting globals and locals

One way to minimize the security issues of eval() is to restrict the use of globals and locals. Globals refers to the variables defined in the program, while locals are variables defined within the eval() function.

Typically, when eval() is called, it allows access to all these variables and functions. However, by providing only a limited subset of these variables, we can reduce the risk of code injection.

To restrict access to these variables, we can pass a dictionary of allowed global and local variables as an argument to eval(). By restricting the variables, we can limit the user’s input to prevent damage, even if it’s malicious.

A more secure method is to use namespaces, which allow you to have several dictionaries of variables, and you can choose to restrict some of them before running eval().

Restricting the Use of Built-In Names

Pythons built-in names are methods and functions provided by Python in the built-in namespace. These functions can be potentially used by attackers to gain control over the program.

Therefore, it is vital to limit the usage of these functions to only trusted sources when calling them with eval(). To restrict the use of built-in names, you can use the __builtin__ module, which contains all the built-in functions for the Python interpreter.

In Python 3.x, you can use the built-in module that is built for this specific purpose. You need to build a dictionary of allowed functions and set the built-in module’s functions to this dictionary.

This enables you to enforce policies limiting the use of these potentially dangerous methods.

Restricting Names in the Input

When using eval() with input(), the user can potentially inject code and compromise its security. To avoid this, we need to sanitize the input, allowing only safe and trusted code for evaluation within the function.

One way of doing this is by mapping the input to a set of allowed strings, making sure no malicious code can slip in. Another method of restricting the names in the input is to use the ast module, which can parse and evaluate an expression without executing it.

Thus, it can check the input expression’s validity before passing it to eval(). The ast module also provides a whitelist of names used in the input, allowing only the allowed names to be used.

Restricting the Input to Only Literals

A literal is a value expressed exactly as it was intended to be interpreted by Python. These include strings, integers, floating-point numbers, and others.

By restricting eval() to accept only literals, we can prevent the user from injecting and running malicious code. To limit eval() to only process literals, we can use the literal_eval() function included in the ast module.

This function evaluates only literals and returns their value. Code injections are not allowed, and any code that doesn’t conform to the strict literal syntax will raise an exception.

Building a

Math Expressions Evaluator

Using all the techniques, we mentioned, we can create an evaluator that is safe and efficient. Here is an example of a simple evaluator:

import ast

import operator

allowed_globals = {‘__builtins__’: None, ‘abs’: abs, ’round’: round, ‘math’: None}

def evaluate(expression):

tree = ast.parse(expression, mode=’eval’)

allowed_names = {node.id for node in ast.walk(tree) if isinstance(node, ast.Name)}

for name in allowed_names:

if name not in allowed_globals:

raise NameError(‘Name not allowed: {name}’)

code = compile(tree, ‘‘, mode=’eval’)

return eval(code, allowed_globals)

This math expression evaluator creates a new dictionary of allowed global variables.

The function then inserts the abs and round functions and a global module, math, from which mathematical functions can be accessed. It parses the expression given using the ast.parse() method.

You can check specifically for allowed variables such as names and functions before compiling and executing the code using eval().

Conclusion

The eval() function is useful for dynamically evaluating code, but it can pose significant security risks if you don’t take extra measures to secure it. Restricting accesses to variables and namespaces, using the ast module to restrict names and literals as inputs, and creating a whitelist of allowed built-ins are some methods you can use to help reduce security concerns.

By carefully controlling the functionality of eval(), it still remains very powerful and useful for a wide range of applications. In conclusion, the article outlines the potential security risks associated with Python’s eval() function and provides methods to minimize these risks.

By restricting access to variables and namespaces, limiting the use of built-in functions, restricting names in input, and only allowing literals, you can ensure the safety of your code. Incorporating these security measures into Python code is essential to keep it safe from malicious attacks.

Eval() remains a powerful tool that can be used for a wide range of applications when utilized safely. Nonetheless, the importance of securing this function cannot be overstated, and it is essential to remain cautious while using it.

Popular Posts