Enabled default credentials - Python

Enabled default credentials - Python

Need

Implementation of strong, unique credentials for system resources

Context

  • Usage of Python 3 for writing and executing Python code
  • Usage of Django for building web applications in Python

Description

Non compliant code

        from django.db import models

class MyModel(models.Model):
    # ...
    def my_custom_sql(self, sql, params):
        from django.db import connection
        with connection.cursor() as cursor:
            cursor.execute(sql, params)
            row = cursor.fetchone()

        return row
        
        

The above code is a Django model that includes a custom SQL method. This method takes SQL and parameters as input, and then executes that SQL directly against the database using the Django database connection.

This code is vulnerable because it uses the default Django database connection, which has default credentials. If these credentials are weak or well-known, an attacker could potentially guess them and gain access to the database.

Furthermore, the method executes raw SQL directly. This means that if an attacker can control the SQL or the parameters that are passed to this method, they may be able to execute arbitrary SQL against the database. This could lead to data leakage, data corruption, or even total loss of data.

The vulnerability can be exploited if the attacker has access to the system where the application is running or if the application is not properly secured and allows the attacker to inject SQL.

To fix this vulnerability, you should:

1. Not use default or well-known credentials for your database. Use strong, unique credentials and store them securely. 2. Avoid executing raw SQL directly. Use Django's ORM to interact with the database, which will automatically handle escaping and other security concerns. 3. If you must use raw SQL, be sure to properly escape any user-controlled input to prevent SQL injection attacks. 4. Secure your application to prevent attackers from being able to inject SQL or access sensitive parts of the system.

Steps

  • Remove any hardcoded credentials from the codebase.
  • Use environment variables to store sensitive information such as database credentials.
  • Implement strong password policies and change default passwords.
  • Use a secure method to store and retrieve credentials, such as a secure vault or a configuration management system.
  • Regularly rotate and update credentials.
  • Implement access controls to limit who can access the credentials.

Compliant code

        import os
from django.db import models

class MyModel(models.Model):
    # ...
    def my_custom_sql(self, sql, params):
        from django.db import connection
        with connection.cursor() as cursor:
            cursor.execute(sql, params)
            row = cursor.fetchone()

        return row
        
        

The above code is a Django model with a custom SQL method. The method opens a connection to the database and executes a SQL query. However, the code does not specify any database credentials, which means it's using the default credentials. This is a security vulnerability as it allows anyone with knowledge of the default credentials to access the database.

To fix this vulnerability, we need to remove the use of default credentials and instead use secure methods to store and retrieve database credentials. One common method is to use environment variables. These are variables that are set in the environment where the application is running, and can be accessed by the application at runtime. This way, the credentials are not hardcoded into the application code, and can be changed without modifying the application.

Here is the fixed code:

                import os
from django.db import models

class MyModel(models.Model): # ... def my_custom_sql(self, sql, params): from django.db import connection with connection.cursor() as cursor: # Use environment variables to get the database credentials username = os.getenv('DB_USERNAME') password = os.getenv('DB_PASSWORD') # Set the credentials on the connection connection.settings_dict.update({ 'USER': username, 'PASSWORD': password, }) cursor.execute(sql, params) row = cursor.fetchone()

return row


In the fixed code, we use the os.getenv function to get the database username and password from the environment variables DB_USERNAME and DB_PASSWORD. We then update the connection settings with these credentials before executing the SQL query.

Remember to set these environment variables in the environment where your application is running. Also, make sure to implement strong password policies and regularly rotate and update these credentials. Implement access controls to limit who can access these environment variables.

References