1. Use Strong Hashing for Passwords
When handling passwords, always hash them rather than storing them in plaintext. Hashing is a one-way encryption, so the original data cannot be reconstructed from the hash.
Recommended Library: bcrypt or argon2
Example:
import bcrypt
# Hash a password
password = "super_secure_password"
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
# Verify password
is_valid = bcrypt.checkpw(password.encode('utf-8'), hashed_password)
if is_valid:
print("Password is correct!")
2. Use HTTPS for Communication
Always use HTTPS (TLS/SSL) to encrypt communication between the client and server. This protects sensitive data, such as passwords and personal information, from being intercepted by attackers.
Make sure you configure your web server (e.g., Nginx, Apache) to serve your application over HTTPS.
For local development, you can use tools like ngrok
to create a secure tunnel.
3. Encrypt Sensitive Data at Rest
For sensitive data that needs to be stored (e.g., personal user information), it's a good practice to encrypt it before saving it to a database or filesystem.
Recommended Libraries: cryptography, PyCryptodome
Example using cryptography:
from cryptography.fernet import Fernet
# Generate a key (keep it safe)
key = Fernet.generate_key()
cipher = Fernet(key)
# Encrypt data
data = "This is sensitive data".encode('utf-8')
encrypted_data = cipher.encrypt(data)
# Decrypt data
decrypted_data = cipher.decrypt(encrypted_data)
print(decrypted_data.decode('utf-8'))
Key Management: Store the encryption keys securely, perhaps in a secrets manager (AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault). Avoid hardcoding keys in the application code.
4. Use Environment Variables for Sensitive Keys
Store sensitive configuration settings, such as database credentials or API keys, in environment variables rather than hardcoding them in your source code. This helps prevent accidental leaks of sensitive information.
Example:
Set the environment variable in your terminal:
export DB_PASSWORD="your_secure_password"
Access the environment variable in Python:
import os
db_password = os.getenv('DB_PASSWORD')
5. Encryption for Sessions and JWT Tokens
For authentication, consider using JSON Web Tokens (JWT) to maintain sessions. You can encrypt the contents of the JWT using the PyJWT library and a secret key.
Example:
import jwt
import datetime
# Secret key to encode and decode JWT
SECRET_KEY = 'your_secret_key'
# Create a token
payload = {
'user_id': 123,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1) # Expiration time
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
# Decode and validate the token
try:
decoded_token = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
print(decoded_token)
except jwt.ExpiredSignatureError:
print("Token has expired.")
except jwt.InvalidTokenError:
print("Invalid token.")
6. Use Secure Storage for File Uploads
If your application allows users to upload sensitive files (e.g., documents or photos), make sure to:
Encrypt files before storing them on the server.
Store files in secure locations with proper access control.
Validate file types and sizes before uploading to prevent malicious uploads.
Example (Encrypting files):
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os
def encrypt_file(file_path, key):
iv = os.urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend())
encryptor = cipher.encryptor()
with open(file_path, 'rb') as f:
file_data = f.read()
encrypted_data = encryptor.update(file_data) + encryptor.finalize()
with open(f"{file_path}.enc", 'wb') as f:
f.write(iv + encrypted_data)
# Example usage:
key = os.urandom(32) # AES-256 requires a 32-byte key
encrypt_file("sensitive_file.txt", key)
7. SQL Injection Protection
To prevent SQL injection attacks, always use parameterized queries or ORM (Object-Relational Mapping) frameworks.
Example using psycopg2 (PostgreSQL):
import psycopg2
conn = psycopg2.connect(dbname='testdb', user='user', password='password')
cur = conn.cursor()
username = 'john'
cur.execute("SELECT * FROM users WHERE username = %s", (username,))
result = cur.fetchall()
Example using an ORM (SQLAlchemy):
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///example.db')
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String)
Session = sessionmaker(bind=engine)
session = Session()
user = session.query(User).filter_by(username='john').first()
print(user)
8. Auditing and Logging
Logging is essential to identify potential security issues. Make sure to:
Log failed login attempts.
Log access to sensitive data or actions (like changing a password or making a payment).
Ensure logs are stored securely and don't include sensitive information like passwords or credit card numbers.
9. Regular Security Updates and Dependency Management
Keep your libraries and dependencies up to date. Regularly check for security vulnerabilities using tools like Dependabot
or Snyk
.
Use a virtual environment (venv or conda) to isolate dependencies and minimize conflicts.
10. Use Multi-Factor Authentication (MFA)
For critical actions (e.g., account changes, financial transactions), enforce multi-factor authentication (MFA). This adds an additional layer of protection by requiring the user to provide a second form of verification (like a code sent via SMS or an authenticator app).
Learn Fullstack Python Training in Hyderabad
Read More
Common Web Security Vulnerabilities and How to Protect Against Them
Encrypting Sensitive Data in Full Stack Python Apps
At Our Quality Thought Training Institute in Hyderabad
Subscribe by Email
Follow Updates Articles from This Blog via Email
No Comments