API Security: Best Practices for Python Developers - Part II

Part II of the Developer’s Guide for a secure API implementation. Devs are the core of web applications, that's why you should continue learning how to prevent common attacks and secure your endpoints correctly. Avoid deploying vulnerable code by taking into account these Security Best Practices.

· 7 min read
API Security: Best Practices for Python Developers - Part II

We are here to show you the OWASP Top 10 API Security to develop secured coding and stand out from other developers. We covered the first five Security Best Practices in a previous blogpost. Make sure to give it a look if you haven't already. Know your vulnerabilities!

Let's continue enumerating Security Best Practices!

6. Update just the necessary data.

Vulnerability: Mass Assignment

Objects in web applications usually contain many properties, which sometimes need to be updated by the users, like user["name"], user["address"] or user["email"]. However there are some properties that are set by the application, and should not be modified or accessed by the user. Like user["admin"], user["role"] or user["id"]

An API endpoint is vulnerable to Mass Assignment if it automatically converts client input into internal object properties, without first validating which parameters are being updated and saved.

# Vulnerable endpoint
@app.route("/user/email", methods=["PATCH"]) 
def update_email():
  user = get_user_information()
  user_input = request.data

  # Merges input to the user object without validation or sanitization
  msg = "Email updated successfully."
  return msg, 200

Bad actors can modify request's bodies to update or overwrite sensitive object’s properties that developers never intended to expose, leading to privilege escalation, data tampering, security mechanisms bypass, and more.

In the example above , the application thinks that request.data is secure, with only {"email": "user@email.com"} as body because there is only one "Email Input" displayed on the web's UI for users to update their emails when necessary. However, instead of checking that email is the only key in the JSON input, or just grabbing that key, the back-end is appending both pieces of data, without verifying the information they contain.

If instead of a user, we have a bad actor using the API then it may try to update more sensitive information to gain privileged access to the application. Modifying request.data to contain both email and admin values like {"email": "user@email.com", "admin": True} , when processed, it will not only update the user's email, but add an admin key to the object if it didn't exist or override it with the new value if present. Making the user now have administrator privileges.

How to fix this vulnerability

# Secure endpoint
@app.route("/user/email", methods=["PATCH"]) 
def update_email():
  user = get_user_information()
  user_input = request.data

  # Merges only the necessary data
  user["email"] = user_input["email"]
  msg = "Email updated successfully."
  return msg, 200

Other tips for fixing and preventing Mass Assignment vulnerabilities:

  • If possible, avoid using functions that automatically bind a client’s input into code variables or internal objects.
  • Whitelist only the properties that should be updated by the client.
  • Use built-in features to blacklist properties that should not be accessed by clients.
  • If applicable, explicitly define and enforce schemas for the input data payloads.

7. Check all your default settings.

Vulnerability: Security Misconfiguration

This vulnerability can take many forms and shapes. Attackers will often attempt to find unpatched versions of frameworks or dependencies the application is using; common configurations or debugging endpoints; or unprotected files and directories to gain unauthorized access or knowledge of your system.

Because of this, security misconfiguration can happen at any level of the API stack, from the network level to the application level. And they can not only expose sensitive user data, but also system details that may lead to full server compromise.

For example, in the case above, you can see several security misconfigurations, which also lead to further exploitation:

1. An admin panel that is open to the internet, instead of locally accessible, it may even use default credentials.
2. It's using insecure protocol because it's not communicating via HTTPS.
3. Framework fingerprints are visible, for both PHP and MySQL. If you dig deeper, you can also check the NGINX information.
4. The previous point leads to further exploitation because you can see with a quick search that phpMyAdmin 2.2.0 has a directory traversal vulnerability and MySQL 4.0.26 has more than one known vulnerability.
5. There is also leakage of sensitive data, because you can check runtime information, system variables and processes; as well as the /sql/phpinfo.php endpoint.

Other tips for fixing and preventing Security Misconfiguration vulnerabilities:

  • Obfuscate fingerprint when possible.
  • Make sure debugging is turned off on production environments.
  • Never use default credentials.
  • Use the respective secure headers via a secure communication channel for all API interactions, including static assets.
  • Make sure your dependencies and frameworks are up to date.
  • Lock down every environment with its own proper configuration depending on its usage.
  • Erase all default configuration that is not being actively used.
  • Review and update configurations across the entire API stack. The review should include: orchestration files, API components, and cloud services (e.g., S3 bucket permissions).
  • Continuously assess the effectiveness of the configuration and settings in all environments.

8. Don't trust user input, never!

Vulnerability: Code Injection

Bad actors will feed the API with malicious code through whatever injection vectors are available, such as user inputs, url parameters, integrated services configurations, etc, expecting it to be sent to an interpreter that executes them.

This happens mainly because client-supplied data is not validated, filtered, or sanitized by the API back-end before being used or concatenated to SQL/NoSQL/LDAP queries, OS commands, XML parsers, and Object Relational Mapping (ORM)/Object Document Mapper (ODM). As mentioned in the Part I, don't only trust on your front-end for input validations, they can be easily bypassed, make sure to always validate in the back-end as well.

# Vulnerable endpoint
@app.route("/document", methods=["DELETE"])
def delete_document():
  # Just deletes document without validating or sanitizing user input.
  status = os.system("rm ./documents/" + filename)
  if status == 0:
    msg = "Document deleted."
    return msg, 200
      msg = "Something went wrong."
      return msg, 500

In this case, you can see that if user sends a POST request body like {"filename": "document.pdf"}, then it would get deleted due to the system's call to the rm command. However, the back-end logic is not validating whether the input is safe or if it contains something that shouldn't be there.
For example, what would happen if the user sends a POST request body like {"filename": "document.pdf ; rm /"}. You are right, the application would run the rm command to delete document.pdf and then it would proceed to delete the whole root directory of the server.

How to fix this vulnerability

# Secure endpoint
@app.route("/document", methods=["DELETE"])
def delete_document():
  # Validates user input.
  pattern = r'^[\w,\s-]+\.(pdf|PDF)$'
  valid_file = bool(re.match(pattern, filename))

  # Validates that the document exists.
  if valid_file:

    # Proceeds to remove document.
    status = os.remove("./documents/" + filename)
    if status == 0:
      msg = "Document deleted."
      return msg, 200
    msg = "The filename is not valid."
    return msg, 422

Other tips for fixing and preventing Injection vulnerabilities:

Preventing injection requires keeping data separate from commands and queries.

  • Perform data validation using a single, trustworthy, and actively maintained library.
  • Validate, filter, and sanitize all client-provided data, or other data coming from integrated systems.
  • Special characters should be escaped using the specific syntax for the target interpreter.
  • Always limit the number of returned records to prevent mass disclosure in case of injection.
  • Validate incoming data using sufficient filters to only allow valid values for each input parameter.
  • Define data types and strict patterns for all string parameters.

9. Documentation is everything.

Vulnerability: Improper Assets Management

If there is no updated documentation of all API versions deployed it's quite easy to miss one or two things along the way. The lack of assets inventory and retire strategies leads to running unpatched systems, resulting in leakage of sensitive data.

It’s common to find unnecessarily exposed API hosts because of modern concepts like microservices, which make applications easy to deploy and independent from each other. Old API versions are an easy way to compromise systems without having to fight state-of-the-art security mechanisms, which might be in place to protect the most recent API versions.

Bad actors may gain access to sensitive data, or even takeover the server through old, unpatched API versions still connected to valid databases or that have in place less security configurations or backdoors to make testing easier.

Other tips for fixing and preventing Improper Assets Management vulnerabilities:

  • Inventory all API hosts and document important aspects of each one of them, focusing on the API environment (e.g., production, staging, test, development), who should have network access to the host (e.g., public, internal, partners) and the API version.
  • Inventory integrated services and document important aspects such as their role in the system, what data is exchanged (data flow), and its sensitivity.
  • Document all aspects of your API such as authentication, errors, redirects, rate limiting, cross-origin resource sharing (CORS) policy and endpoints, including their parameters, requests, and responses.
  • Generate documentation automatically by adopting open standards and available libraries. Include the documentation build in your CI/CD pipeline.
  • Use external protection measures such as API security firewalls for all exposed versions of your APIs, not just for the current production version.
  • Avoid using production data with non-production API deployments. If this is unavoidable, these endpoints should get the same security treatment as the production ones.
  • When newer versions of APIs include security improvements, perform risk analysis to make the decision of the mitigation actions required for the older version: for example, whether it is possible to backport the improvements without breaking API compatibility or you need to take the older version out quickly and force all clients to move to the latest version.

10. Configure and analyze logs periodically.

Vulnerability: Insufficient Logging & Monitoring

Attackers may take advantage of lack of logging and monitoring to abuse systems without being noticed, as it's almost impossible to track suspicious activities and respond to them in a timely fashion.

Without visibility over ongoing malicious activities, attackers have plenty of time to fully compromise systems without being detected.

Other tips for fixing and preventing Insufficient Logging & Monitoring vulnerabilities:

  • Log all failed authentication attempts, denied access, and input validation errors.
  • Logs should be written using a format suited to be consumed by a log management solution, and should include enough detail to identify the malicious actor.
  • Logs should be handled as sensitive data, and their integrity should be guaranteed at rest and transit.
  • Configure a system to continuously monitor the infrastructure, network, and the API functioning.
  • Use a Security Information and Event Management (SIEM) system to aggregate and manage logs from all components of the API stack and hosts.
  • Configure custom dashboards and alerts, enabling suspicious activities to be detected and responded to earlier.

Time to take action

If you ended up here with us is because you're interested in improving your developer skills by implementing Security Best Practices. We guided you here, now it's your turn to assess your API and patch any vulnerabilities you may have.

Did you like what you read? Because we have several technical blogs like this one waiting for you. Check them out here!


Check out our other social media platforms to stay connected:‎

Website | www.vidocsecurity.com
Linkedin | www.linkedin.com/company/vidoc-security-lab
X (formerly Twitter) | twitter.com/vidocsecurity
YouTube | www.youtube.com/@vidocsecuritylab
Facebook | www.facebook.com/vidocsec
Instagram | www.instagram.com/vidocsecurity