Introduction
Dear readers, today I want to discuss a particularly important topic - Python data security programming. As a Python developer, I deeply understand the importance of data security for every project. Let's explore together how to write more secure Python code.
Injection Attacks
When it comes to security vulnerabilities, SQL injection and command injection are among the most common and dangerous. I remember making a typical mistake when I first started learning Python. Let's look at this code:
username = input("Enter username: ")
password = input("Enter password: ")
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(query)
This code looks simple and intuitive, but actually contains huge security risks. If someone enters admin' --
in the username field, the query becomes:
SELECT * FROM users WHERE username='admin' --' AND password=''
This bypasses the password verification. Therefore, we should use parameterized queries:
import sqlite3
def safe_login(username, password):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
query = "SELECT * FROM users WHERE username=? AND password=?"
cursor.execute(query, (username, password))
result = cursor.fetchone()
conn.close()
return result is not None
This function uses parameterized queries, effectively preventing SQL injection attacks. This seemingly simple modification can significantly improve our application's security.
Data Encryption
When it comes to data security, encrypted storage is a crucial topic. Have you considered that if the database is breached, plaintext stored passwords would all be exposed? Let me share a secure password storage solution:
import hashlib
import os
def hash_password(password):
# Generate random salt
salt = os.urandom(32)
# Hash combination of salt and password
key = hashlib.pbkdf2_hmac(
'sha256',
password.encode('utf-8'),
salt,
100000
)
return salt + key
def verify_password(stored_password, provided_password):
# Extract salt from stored password
salt = stored_password[:32]
stored_key = stored_password[32:]
# Hash provided password using same salt
key = hashlib.pbkdf2_hmac(
'sha256',
provided_password.encode('utf-8'),
salt,
100000
)
return key == stored_key
This code uses the PBKDF2 (Password-Based Key Derivation Function 2) algorithm to encrypt passwords. It not only uses a hash function but also incorporates salt and multiple iterations, making it extremely difficult to crack. I particularly like this solution because it's both secure and easy to implement.
Secure Transmission
When it comes to data transmission security, HTTPS is essential. Let's look at how to implement a simple HTTPS server in Python:
from http.server import HTTPServer, SimpleHTTPRequestHandler
import ssl
def run_https_server(port=4443):
httpd = HTTPServer(('localhost', port), SimpleHTTPRequestHandler)
# Configure SSL certificate
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain('server.crt', 'server.key')
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
print(f'Server running on https://localhost:{port}')
httpd.serve_forever()
if __name__ == '__main__':
run_https_server()
This example shows how to create a basic HTTPS server. Of course, in actual production environments, we typically use more mature web frameworks like Django or Flask, which have good HTTPS support.
Dependency Management
Did you know that many security vulnerabilities actually come from outdated dependencies? I often use this code to check the security of project dependencies:
import pkg_resources
from packaging import version
import requests
import json
def check_package_security(package_name):
try:
installed_version = pkg_resources.get_distribution(package_name).version
# Get package information from PyPI
response = requests.get(f'https://pypi.org/pypi/{package_name}/json')
data = response.json()
latest_version = data['info']['version']
if version.parse(installed_version) < version.parse(latest_version):
print(f"Warning: {package_name} version is outdated")
print(f"Current version: {installed_version}")
print(f"Latest version: {latest_version}")
else:
print(f"{package_name} version is up to date")
except Exception as e:
print(f"Error checking {package_name}: {str(e)}")
Logging
Security logs are crucial for detecting and investigating security issues. Here's my commonly used logging configuration:
import logging
from logging.handlers import RotatingFileHandler
import os
def setup_security_logging():
# Create logger
logger = logging.getLogger('security_logger')
logger.setLevel(logging.INFO)
# Create handler
log_file = 'security.log'
handler = RotatingFileHandler(
log_file,
maxBytes=10*1024*1024, # 10MB
backupCount=5
)
# Create formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
# Add handler to logger
logger.addHandler(handler)
return logger
def log_security_event(logger, event_type, details):
message = f"Security event: {event_type} - {details}"
logger.info(message)
Deserialization Security
Speaking of deserialization security, I must mention Python's pickle module. While this module is convenient, it can lead to serious security issues if used improperly. Let's look at a secure deserialization implementation:
import json
from typing import Any, Dict
class SafeDeserializer:
def __init__(self, allowed_types: set):
self.allowed_types = allowed_types
def deserialize(self, data: str) -> Any:
try:
parsed_data = json.loads(data)
return self._validate_and_convert(parsed_data)
except json.JSONDecodeError:
raise ValueError("Invalid JSON data")
def _validate_and_convert(self, obj: Any) -> Any:
if isinstance(obj, dict):
return self._validate_dict(obj)
elif isinstance(obj, list):
return [self._validate_and_convert(item) for item in obj]
elif type(obj).__name__ in self.allowed_types:
return obj
else:
raise ValueError(f"Disallowed data type: {type(obj).__name__}")
def _validate_dict(self, obj: Dict) -> Dict:
return {
str(k): self._validate_and_convert(v)
for k, v in obj.items()
}
Conclusion
Security programming is a continuous learning process. As we've seen, from input validation to encrypted storage, from secure transmission to dependency management, each aspect requires our careful attention.
What do you think about the security practices we discussed today? Have you encountered similar security issues in your actual development work? Feel free to share your experiences and thoughts in the comments.
Remember, security is not a one-time task but a process that requires continuous attention and updates. Let's work together to write more secure Python code.