The platform-agnostic language may be easy to learn, but that can lead to security vulnerabilities unless these safety guidelines are heeded
Like all programming languages, Python is not immune to security threats.
To prevent attackers, secure coding best practices must be adopted.
Following a six best practices that should employed when building secure applications.
- Upgrade, update, patch
Always use up-to-date code to make sure that your software will work without issues and will not open doors for attackers. If we compare Python versions 2 and 3, there are major security advancements in the later release that should help keep your software secure.
As Python versions are not fully compatible with each other, developers may be required to rewrite a lot of code in order to move to later versions. However, the improvements to Python 3.x on the security front make updating not only worthwhile but important. Those changes are
- Default Unicode encoding of strings
- Changes to error-handling and exception syntax and semantics of raising/catching an exception
- Configuration and behavior of popular XML libraries
- Changes to eval and input functions
- Inclusion of OpenSSL 1.0.2k in the core runtime libraries
Developers working with older versions of code (those no longer supported by Python) need to make sure to validate inputs or avoid calls implemented through dangerous functions—such as those that do shell or process executions.
Python 3.x changes language syntax and semantics in a way that is not backward-compatible, so a simple migration of larger codebases is not easy and will introduce substantial challenges, but it is nevertheless advisable. Another advantage of Python is its big community that takes care of reported security flaws quickly, such as users in this site.
- Sharing can be scary
It can be difficult to ensure that the packages you pull from the Python Package Index (PyPI) are safe for your project. Although PyPI gives package maintainers the option of signing their submissions so that adopters can validate the download’s integrity and the author’s identity, it is important to keep in mind that packages in the PyPI do not go through a security review.
Let us start with license compliance: Projects are published under a variety of licenses and each has its own license obligations. However, regardless of license type, you need to fulfil all license obligations in order to avoid legal issues. You may want to avoid certain licenses entirely to avoid losing your intellectual property.
Next, adhering to Python security best practices means making sure that your code is free of vulnerabilities and bugs, so users and customers can use it without danger. There are two types of code to consider here. One is proprietary code—the code that you wrote. Proprietary code is best checked with a static application security testing (SAST) tool to finds errors introduced during development that could make your code insecure.
The second is the code you get from others. Open source or third-party code—including the dependencies in your code (both direct and transitive)—is best handled by an SCA tool to uncover information about the packages used, including their licensing, security, and operational risk state.
Using both SAST and SCA tools helps uncover errors early in the software development life cycle, rather than later when they are more expensive and time-consuming to address.
Secure ways to manage inputs, package names, and import types
- Sanitize inputs
User inputs can be highly dangerous, as they can lead to possible injection attacks. One of the most common and simple injection attacks is SQL injection.
To prevent this, some web platforms limit the special characters that can be included in usernames and passwords. Unfortunately, this makes the creation of strong passwords more difficult. Therefore, it is best to sanitize the inputs: create rules defining valid inputs, acceptable character sequences, and which combinations to allow. This helps prevent injection attacks while still allowing strong passwords.
- Use prepared statements
Make sure your database supports prepared statements, which can protect against vulnerabilities like SQL injection—and in some cases, even result in performance improvements SQL statements are run repeatedly.
In Python, you can use prepared statements even if your database does not support them. The biggest security benefit of using prepared statements is the separation of SQL statements and user-provided data. This ensures that user-provided data cannot be abused to modify SQL statements, and will be used literally in the precompiled statement so that the logic will not change.
- Check your spelling
Malicious actors often create misspelled domains to catch people that have mistyped a URL. The same can happen when fetching libraries from PyPI.
A malicious package with a name similar to a legitimate one could be placed in a repository to trick someone into fetching it by mistake!
- Avoid implicit relative import
There are two types of relative imports:
- The explicit relative import requires you to specify the exact path of the module relative to the current module
- The implicit relative import does not specify the resource path at all
The danger of implicit relative imports is that a poisoned package could find its way into another part of your project (via an import of another library) and then could mistakenly be used instead of the library you intended.
Due to the unspecified path and the potential for confusion, the implicit relative import was removed from Python 3.x. However, if you are still using older versions of Python, remove implicit relative imports and use other import types.
- Sanitize inputs
- Being careful is good, but segmentation is better
Using virtual environments is a Python security best practice not only for security reasons, but also to help keep your development environments organized.
When you set up a virtual environment for your project, you must ensure that all the packages needed are available and isolated from other projects on your system. This helps avoid collisions and conflicts between libraries.
Virtual environments are also great for those using Python 2.7 and looking for a good way to start projects with Python 3.x, as you can set up a virtual environment that will use Python 3.x without impacting the projects using Python 2.7.
And virtual environments enable you to contain any malicious packages you may have inadvertently pulled, so you can avoid affecting your whole system.
- Keep secrets secret
Ever heard the saying “the internet never forgets”? This is true for images and media, and it is true for any secrets you distribute with your code.
Developers sometimes hardcode sensitive information such as passwords, URLs with authentication information and API keys to make testing easier. This is a bad practice because such hardcoded secrets can be forgotten about and then committed to a code repo like GitHub or similar platform. Once this happens, those secrets will be included in databases or logs for anyone to see.
Make sure that anything you upload: code, readme and configuration files, and especially plain text files—is free of secret information of any kind.
- Hide information users should not see
We all know the trial-and-error paradigm in development. You code and test, and based on the outcome, adjust your code and test again. This is a never-ending process that ensures an ongoing supply of good debugging information. That is why development environments usually display all debugging output.
And that is why it is important to separate the development environment from the production environment. Debugging information on your production system is a security hazard. If the environments are not separated, every bug will be communicated to public users, so a malicious actor could get information on how to breach your systems.
Switch off any debugging information on the production systems that could be publicly visible, and replace those notifications about issues with exception-handling code that places the information on your internal bug-tracking systems. Users should see only a generalized explanation of the error if needed.
While not displaying debugging information is recommended, you still need to fix the issues. Take care of all debugging before the system is taken into production. SAST and SCA tools are highly advisable. Good SAST tools uncover any development mistakes that could lead to vulnerabilities in your proprietary code, and good SCA tools check open source components and their direct or transitive dependencies for any risks they bring into your code.
These tests help make sure you get rid of security risks in your code before production.
I hope that this overview of Python security best practices gave you some easy tips for developing secure applications with Python.