Two decades ago there were ‘only’ a few tens of thousands of malware samples. Now, the AV-test institute reports that they identify 350,000 new samples a day. This makes security a key part of any product development. Read on to learn how to secure your Python code.

What Is Secure Coding?

The term secure coding refers to developing programs in a way that protects against the introduction of vulnerabilities into source code. This includes defects, bugs and logic flaws. Secure coding is the best way to avoid dealing with vulnerability exploits down the line. It’s about eliminating vulnerabilities in source code, thus limiting exploit flaws.

Security Best Practices for Python Programming

Many issues that are common in lower-level languages have less of an impact in Python. Issues like memory leaks and buffer overflow are much easier to avoid. This is in comparison to using languages like C or C++. Python avoids these issues with features like garbage collection, which automatically removes old items from memory. Still, Python has vulnerabilities of its own which can be addressed with the best practices below.

Sanitize Inputs

Python is just as vulnerable to injection attacks as any other language. Injection attacks occur when malicious code is inserted by harmful parties via user input. Anytime your program receives arguments from a user, you face a security risk. An effective way of dealing with this is through “sanitizing” user inputs.

In the case of string input prompts, this risk can stem from the use of SQL injections. This form of injection is often used to gain privileges and access that can lead to further breaches. Another form of injection occurs when calling processes that rely on file names provided by the user. There are numerous ways to exploit this direct access to your system shell.

Sanitizing inputs refers to the removal of harmful characters or unexpected script commands from an input. It can be done using a variety of means. There is a single theme to all of them; take the input and check that it’s what you intended it to be.

Common ways of doing this include checking inputs against regular expressions or parameterizing them. Regular expressions define exactly what characters or the order of characters a user is allowed to input. Parameterization refers to assigning user inputs to a variable rather than using them directly.

Avoid Dangerous Functions

You can usually avoid the risk of code injections by not running user input as commands or script. There are two main kinds of functions that lead to dangerous vulnerabilities of this sort: code injectors and command injectors.

Code injectors take user input and interpret it as code. Command injectors are used to run applications from the command-line from within an application.

In the code injector category, the most notable functions are eval() and exec(). These functions can come in handy at times, and may be tempting to use, but create significant risk. If you must use them, sanitize your input first.

In the command injector category, the subprocess module is probably the most commonly used. The subprocess module is used to create new processes or run new programs from within an existing program.

A lot of the dangers of subprocess.call() can be avoided. This is accomplished by leaving the default argument of shell=False. Changing it to shell=True means that the provided command will run through the shell itself. This is strongly unrecommended for any unknown input.

Eliminate Implicit Relative Imports

If you are still using Python 2, a major risk comes from using implicit relative imports. In Python 3, relative imports must be explicit, eg. from python import monty. However, in Python 2 you may use implicit relative imports, eg. import monty.

The issue lies in the fact that this function finds the first instance of the name of the module. It will not necessarily locate the one the developer intended. This is a great way to import malicious modules, and should always be avoided. Thankfully, this functionality has been deprecated in Python 3. It should become less of an issue as time passes.

Keep in mind that packages that can be installed through Python Packaging Index (PyPI) aren’t always scanned for malware. It is your responsibility to check thoroughly that everything you’ve installed is actually safe before using it.

Scan Your Code

There are many programs out there for scanning your code which can save you a lot of headaches after a release. One of the tools available for this is Bandit. Bandit is an open-source program distributed through PyPI.

It’s good for discovering common security issues, and quick and easy to configure for your specific needs. While it will not solve more sophisticated security breaches, it’s a good first step. Once you find a vulnerability, you can use this vulnerability database to learn more about it, check the level of severity, and prioritize fixes accordingly.

Update Your Versions

It’s been over a decade since the official release of Python 3.0. However, Python 2.7 is still fully supported and many developers and companies are still using it. Despite this, the Python Software Foundation has announced that it will no longer support Python 2 as of January 1st 2020. This means that any security issues found after that time will not receive official support, leaving you on your own in dealing with them.

The transition from one version to the next is not easy. Many functions and libraries are incompatible and a lot of tools have changed between the versions. You should begin this process ASAP. The official sunset date is coming very soon.

Conclusion

Security methods are becoming more sophisticated. Unfortunately, attackers continue to have success getting around these methods. Thankfully, although there is a dizzying amount of malicious attacks out there, they mostly fall into one of a few categories.

The best practices and recommendations provided in this article cannot cover every vulnerability. However, using the tips covered here should give you a good start on your way to avoiding common problems and producing secure code in Python.