5 Simple Tips for More Secure Python

Improving your Python Security doesn’t necessarily require a lot of effort or expertise.

Photo by Wade Lambert on Unsplash

Python is an incredibly popular programming language. Chances are if you’re reading this you’re either already using it or will at some point in the future. Stack Overflow’s Annual developer survey has found Python to be the fastest growing major language for 2 years running, and it currently sits behind Javascript in terms of popularity. Likewise, the TIOBE Index, a monthly index of programming language popularity, ranks Python #3 overall and is currently the fastest growing major language. They awarded it the title of language of the year in 2018.

With such popularity it isn’t surprising that python has been the target of malicious dependency attacks among many other potential attack vectors. Additionally, with so many powerful tools available in open-source libraries it’s also easy for developers to misuse or misconfigure these tools and accidentally leak information or privileged access.

Securing your Python application doesn’t need to be time-consuming or difficult however. While it’s certainly possible to dive deep on the subject of application security, and Python security in general. In this post we will look at 5 simple tips that can give you the most bang for your buck and hopefully lead you to more secure applications.

1. Use a modern version of Python

This one should really go without saying, but if you’re still running Python 2.7 in production you should really consider upgrading to Python 3.5 or above.

There are a number of publicly known vulnerabilities in earlier versions of python. For example, CVE-2014–1912 affects python 2.5.x-3.4.x may allow attackers to execute arbitrary code via a crafted string due to a buffer overflow.

In addition to noted vulnerabilities, python 2.x applications may rely on a different dependency tree than 3.x applications because a number of libraries have stopped supporting 2.x. This means that your 2.x application may be stuck using insecure or unsupported libraries in order to offer desired functionality.

Finally, even if security isn’t a concern (which it should be), python 3.5 and above also just offer a generally more intuitive, full-featured experience. Some of the features you’d be missing out on include coroutines with async/await syntax, the new matrix multiplication operator, Literal String Interpolation, more efficient OrderedDict, and much much more.

2. Pin your dependencies

Work smarter not harder, and use pipenv for this.

While pinning your dependencies isn’t always the right move, the notable exception being if you’re publishing a library, keeping tabs on what dependencies you’re pulling in is still a good practice to keep.

While you can pin your dependencies (i.e. using pip freeze) in the classic requirements.txt, pipenv is a handy tool that replaces pip, virtualenv, and the requirements.txt file. Perhaps most importantly, pipenv can help you have deterministic dependency resolution which is good not only for predictable application deployments, but also for ensuring that anyone else working in your application have a similar environment to you.

Whether you decide to use pipenv, or alternative tools like pip-tools, keeping tabs on your dependencies and pinning them for applications can ensure you have secure and predictable builds.

3. Add SAST testing using Bandit

Bandit is a SAST tool maintained by PyCQA that is totally free, quick, and nicely featured. SAST stands for Static Application Security Testing, and is designed to analyze source code, bytecode, or binaries for patterns that are indicative of a security vulnerability. In the case of bandit, it parses your code into an abstract syntax tree (AST) then scans it using a large array of different, configurable plugins before delivering a report and security score for your code.

As mentioned, bandit is free and very easy to integrate into your local development or add to a CI/CD pipeline.

If you aren’t a fan of bandit there are also several alternatives such as pyt (no longer maintained) or focuson from Uber.

4. Watch your import statements

This tip applies at several different levels. First and foremost, when adding a new dependency make sure you’re spelling the package name correctly. There have been numerous instances of typo-sitting in pypi in recent years. While some of these imposter packages appear to be for research purposes, other may be installing malicious code in your system when python executed the setup.py file for the package. We’ll discuss dependency analysis in more detail in the next tip. It’s important to remember that there is no formal vetting process for packages added to pypi.

In addition to making sure you’re adding safe dependencies, there are additional gotchas when importing python modules. If you’re still using python 2.x and using implicit relative imports you may be putting yourself at risk by unknowingly importing malicious code into your code.

A relative import is an import statement that attempts to import from the directory of the current module rather than an absolute import which uses the entire path starting with the root of the module you’re importing. In python 2.x implicit relative imports mean that the location relative to the current module is not specified, so the entire sys.path is checked. If you happen to have another module with the same name in your path before your legitimate target module, that module will be imported and executed instead. All imported python modules are executed on import, so you don’t even need to be calling the malicious module itself for the bad code to be executed.

5. Look into dependency analysis tools

This tip ties back to the previous one. In addition to watching what you import, it’s also important to utilize some kind of dependency analysis (also know as open-source software management or software composition analysis (SCA)) tool to check all of your dependencies for known vulnerabilities (and potentially to ensure that your usage adheres to all of your dependencies’ license requirements).

There are some limited free tools available such as ochrona by ochrona.dev and others. These tools also often have paid versions with additional capabilities. These tools and others like them are typically quite simple to integrate into you CI/CD pipelines but can also be run as-hoc to check new dependencies during the development process.

Wrapping Up

While you can certainly do a serious deep dive into python security, and AppSec in general, following the tips above is a good first step to improving your python security posture.