Basic Security, Python-Centric Approach
Entire libraries can and have been written about secure coding, and secure coding in Python. This blog entry is merely a start, consisting of basic ideas, design patterns, and hopefully are obvious ‘gotchas’. Unfortunately as we in information security have seen over the years, even obvious vulnerabilities keep popping up. Better IDEs and AI models will absolutely help, along with CoPilot software, build tools, and test cases. However, it often pays to go back to the basics. So why don’t we eval() the situation.
Python Security Fundamentals
In an era where digital threats are constantly evolving, secure coding practices have become paramount for software engineers. This essay explores secure coding from the perspective of Python development, encompassing Web APIs, databases, libraries, and CI/CD practices.
Python, despite its reputation for readability and simplicity, is not immune to security vulnerabilities. One of the most critical aspects of secure Python coding is input validation. Consider the following example:
result = eval(user_input)
print(f"Result: {result}")
This code is dangerous because it uses the eval()
function, which can execute arbitrary Python code. A malicious user could input something like __import__('os').system('rm -rf /')
, potentially causing severe damage. Instead, always validate and sanitize user input:
result = int(user_input
print(f"Result: {result}")
except ValueError:
print("Invalid input. Please enter a number.")
Another crucial aspect is managing dependencies securely. The recent PyPI typosquatting attack, where malicious packages with names similar to popular libraries were uploaded, highlights the importance of verifying package sources. Always use pip install
with the --require-hashes
flag and maintain a requirements.txt
file with pinned versions and hashes.
Securing Web APIs
When developing Web APIs, security should be a top priority. The 2021 Twitch data breach, which exposed source code and user data, underscores the potential consequences of API vulnerabilities.
One essential practice is implementing proper authentication and authorization. Consider using industry-standard protocols like OAuth 2.0 or JWT. Here's a basic example using Flask and JWT:
from flask_jwt_extended import JWTManager, jwt_required, create_access_token
app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'your-secret-key' # Change this!
jwt = JWTManager(app)
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username', None)
password = request.json.get('password', None)
if username != 'test' or password != 'test':
return jsonify({"msg": "Bad username or password"}), 401
access_token = create_access_token(identity=username)
return jsonify(access_token=access_token)
@app.route('/protected', methods=['GET'])
@jwt_required
def protected():
return jsonify({"message": "This is a protected endpoint!"})
Database Security
Database security is crucial, as evidenced by the 2019 Capital One data breach, which exposed personal information of over 100 million individuals due to a misconfigured database.
When working with databases in Python, always use parameterized queries to prevent SQL injection attacks. It is also critical to note that while parameterized queries prevent a lot of attacks, it is not foolproof. Care must be taken both in code, schema design, constraints, and features that databases provide that prevent those, “WTH Just Happened” moments. JoT encourages developers become familiar with not only tools like parameterized queries, stored procedures, WAFs, ACID compliance, and ORMs, but understand Why to use What Where.
Additionally, implement proper access controls, encrypt sensitive data at rest, and regularly backup and test your database recovery procedures.
Secure Use of Libraries
Third-party libraries can introduce vulnerabilities into your codebase. The 2017 Equifax breach, which exposed personal data of 147 million people, was caused by an unpatched vulnerability in the Apache Struts framework. Struts developers unavailable for comment.
To mitigate risks:
Regularly update dependencies to their latest secure versions.
Use tools like
safety
to check for known vulnerabilities in your dependencies.Implement a process for vetting new libraries before incorporation into your project.
Also, for a myriad of reasons, consider using tools and environments like setenv or even containers (Docker, chroot, Linux containers) for complex and sensitive applications.
Secure CI/CD Practices
Implementing security in your CI/CD pipeline is crucial for catching vulnerabilities early and preventing their propagation to production. The 2018 British Airways data breach, which exposed customer data due to a compromised third-party script, highlights the importance of securing the entire software supply chain.
Some best practices include:
Integrate static code analysis tools like Bandit into your CI
Implement secrets management using tools like HashiCorp Vault or AWS Secrets Manager.
Use signed commits and enforce code review policies.
Regularly scan container images for vulnerabilities.
By adopting these secure coding practices across Python development, Web APIs, databases, libraries, and CI/CD processes, software engineers can significantly enhance the security posture of their applications. Remember, security is an ongoing process that requires constant vigilance and adaptation to new threats and best practices.
This is a Taste of Python Engineering Security
Check back for more. As attack footprints grow and defensive measures become more complex, learning the principles of secure coding is basic job security.