Using Bandit linter

The OpenStack community (https://www.openstack.org/) created a nice little security linter called Bandit to try to catch insecure code (https://wiki.openstack.org/wiki/Security/Projects/Bandit).

The tool uses the ast module to parse the code such as Flake8 or other linters. Bandit will scan for some known security issues in your code.

Once you've installed it with the pip install bandit command, you can run it against your Python module using the bandit command.

The following script is an example of three unsafe functions. The first one will let you load YAML content that might instantiate arbitrary objects, and the following ones are prone to injection attacks:

    import subprocess 
    from sqlalchemy import create_engine 
    from sqlalchemy.orm import sessionmaker 
    import yaml 
 
    def read_file(filename): 
        with open(filename) as f: 
            data = yaml.load(f.read()) 
 
    def run_command(cmd): 
        return subprocess.check_call(cmd, shell=True) 
 
    db = create_engine('sqlite:///somedatabase') 
    Session = sessionmaker(bind=db) 
 
    def get_user(uid): 
        session = Session() 
        query = "select * from user where id='%s'" % uid 
        return session.execute(query) 

Running Bandit over that script will detect the three issues and explain the problems in detail:

$ bandit bandit_example.py 
... 
Run started:2017-03-20 08:47:06.872002 
 
Test results: 
>> Issue: [B404:blacklist] Consider possible security implications associated with subprocess module. 
   Severity: Low   Confidence: High 
   Location: bandit_example.py:1 
1  import subprocess 
2  from sqlalchemy import create_engine 
3  from sqlalchemy.orm import sessionmaker 
 
-------------------------------------------------- 
>> Issue: [B506:yaml_load] Use of unsafe yaml load. Allows instantiation of arbitrary objects. Consider yaml.safe_load(). 
   Severity: Medium   Confidence: High 
   Location: bandit_example.py:9 
 
 
 bandit_example.py 
8      with open(filename) as f: 
9          data = yaml.load(f.read()) 
10 
 
-------------------------------------------------- 
>> Issue: [B602:subprocess_popen_with_shell_equals_true] subprocess call with shell=True identified, security issue. 
   Severity: High   Confidence: High 
   Location: bandit_example.py:13 
12 def run_command(cmd): 
13     return subprocess.check_call(cmd, shell=True) 
14 
 
-------------------------------------------------- 
>> Issue: [B608:hardcoded_sql_expressions] Possible SQL injection vector through string-based query construction. 
   Severity: Medium   Confidence: Low 
   Location: bandit_example.py:23 
22     session = Session() 
23     query = "select * from user where id='%s'" % uid 
24     return session.execute(query) 
 
-------------------------------------------------- 
 
... 
Files skipped (0): 

For this book, we are using the version Bandit 1.4.0. It has 64 security checks included, and is very easy to extend if you want to create your own checks. You can also tweak its configuration by creating a configuration file in your project.

One security check, for instance, will emit a security warning in case your are running Flask in debug mode, since this is a security issue in production. Consider the following example:

$ bandit flask_app.py 
... 
Test results: 
>> Issue: [B201:flask_debug_true] A Flask app appears to be run with debug=True, which exposes the Werkzeug debugger and allows the execution of arbitrary code. 
   Severity: High   Confidence: Medium 
   Location: flask_app.py:15 
14 if __name__ == '__main__': 
15     app.run(debug=True) 

This is a great check when shipping in production, but when developing your application, you will want to turn this one off. Excluding your test's modules for security scanning is also a good idea.

The following configuration file, which can be used with the ini option will ignore that issue and exclude tests/ files:

[bandit] 
skips: B201 
exclude: tests 
Adding a bandit call in your continuous integration pipeline alongside tools such as coveralls, as described in Chapter 3, Coding, Testing, and Documenting - The Virtuous Cycle, is a good way to catch potential security issues in your code.

In this chapter, we've looked at how to centralize authentication and authorization in a microservices-based application environment using OAuth2 and JWT tokens. Tokens give us the ability to limit what and for how long a caller can do on one of the microservices.

When used with public/private keys, it also prevents an attacker that breaks into one service to break the whole app, as long as it's not the token issuer that's compromised.

Beyond system-level firewall rules, a Web Application Framework is also a good way to prevent some fraud and abuse on your endpoints and is very easy to do with a tool such as ;OpenResty, thanks to the power of the Lua programming language.

OpenResty is also an excellent way to empower and speed up your microservices by doing a few things at the web server level when it does not need to be done within the Flask application.

Lastly, a secure code base is the first step to a secure application. You should follow good coding practices and make sure your code does not do anything stupid when interacting with incoming user data and resources. While a tool like Bandit will not magically make your code safe and secure, it will catch the most obvious potential security issues, so there's no hesitation to continuously run it on your code base.

One part that we did not cover in this chapter is how an end user is securely interacting with our microservices. This is covered in the next chapter, where we will wrap up everything and demonstrate how the Runnerly application can be used through a client-side JavaScript application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset