Inappropriate coding practices - Eval function - Python

Inappropriate coding practices - Eval function - Python

Need

Secure handling of user input and avoidance of using the eval function

Context

  • Usage of Python 3 for scripting and software development
  • Usage of Django for building web applications

Description

Non compliant code

        from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def unsafe_eval(request):
    code_to_run = request.GET.get('code')
    result = eval(code_to_run)
    return HttpResponse(result)
        
        

In the above code, we have a Django view function unsafe_eval that takes in a request object. This function is decorated with @csrf_exempt, which means it is exempted from Cross-Site Request Forgery protection.

The function retrieves a parameter named 'code' from the GET request's parameters using request.GET.get('code'). This parameter is expected to contain a string of Python code.

The real issue lies in the line result = eval(code_to_run). Here, the eval function is being used to execute the string of Python code contained in code_to_run.

The eval function is a built-in Python function that parses the expression passed to it and executes Python code from within the program. If you use it with user-supplied input, it can be a major security risk because it allows arbitrary Python code execution.

In this case, since the 'code' parameter is retrieved directly from the request without any sanitization or validation, an attacker could pass in malicious Python code as the 'code' parameter. This code would then be executed by the eval function, potentially leading to serious security breaches such as Remote Code Execution (RCE), data leakage, or server takeover.

Steps

  • Remove the use of the eval function. It's a dangerous function that can execute any Python code, which makes it a serious security risk.
  • Instead of using eval, consider using safer alternatives like literal_eval from the ast module, which only evaluates Python literals and doesn't execute functions or methods.
  • Validate and sanitize the input data. Never trust user input. Use Django's form validation or create your own validation function to ensure the input is safe before using it.
  • Implement error handling. If the input data is not valid or safe, the application should handle this gracefully and not crash or expose sensitive information.
  • Limit the permissions of the user running the Django application. This can limit the damage if an attacker is able to inject malicious code.

Compliant code

        from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from ast import literal_eval

@csrf_exempt
def safe_eval(request):
    code_to_run = request.GET.get('code')
    try:
        # Validate the input
        if not code_to_run.isidentifier():
            raise ValueError('Invalid input')
        # Use literal_eval instead of eval
        result = literal_eval(code_to_run)
    except Exception as e:
        return HttpResponse(f"An error occurred: {str(e)}")
    return HttpResponse(result)
        
        

The updated code removes the use of the eval function and replaces it with literal_eval from the ast module. The literal_eval function safely parses and evaluates an expression node or a string containing a Python literal or container display. It does not evaluate Python functions or methods, making it a safer alternative to eval.

The code also includes input validation using the isidentifier method. This method checks if the string is a valid identifier according to the Python language definition. If the input is not a valid identifier, a ValueError is raised.

The code is wrapped in a try-except block to handle any exceptions that may occur during the execution of the code. If an exception is raised, the error message is returned in the HTTP response. This prevents the application from crashing and exposing sensitive information.

Finally, the code is run within the safe_eval function, which is decorated with the csrf_exempt decorator. This means that the function is exempt from CSRF protection. This is not recommended in a production environment, as it can open up the application to CSRF attacks. However, it is included here for the sake of the example. In a real-world application, you should always use CSRF protection.

References