[go: up one dir, main page]

0% found this document useful (0 votes)
37 views15 pages

SCT Code

Uploaded by

woviw15402
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views15 pages

SCT Code

Uploaded by

woviw15402
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

File operations are common in Python applications, and handling them securely is essential to

prevent unauthorized access, data corruption, or information leaks. Secure coding practices in file
operations include enforcing permissions, validating paths, handling sensitive data carefully, and
managing errors appropriately.

Here are some secure coding techniques and examples for handling file operations in Python:

1. Use Secure File Permissions

When creating files that contain sensitive information, restrict file permissions so only the necessary
users can access them. This reduces the risk of unauthorized access.

Example

python

import os

def create_secure_file(file_path, content):

"""Creates a file with restricted permissions."""

try:

# Set restrictive permissions (read and write only by the owner)

with open(file_path, 'w') as f:

f.write(content)

os.chmod(file_path, 0o600) # Permissions: rw-------

except Exception as e:

print(f"Error creating file: {e}")

# Usage

create_secure_file("sensitive_data.txt", "This is sensitive information.")

Explanation

Restricted Permissions: The `chmod` command sets permissions to `600`, so only the file owner has
read and write access.

Prevents Unauthorized Access: Limits file access to the application or user that created it, protecting
sensitive information.

2. Validate File Paths to Prevent Path Traversal


When dealing with user-provided file paths, validate and sanitize them to prevent directory traversal
attacks. This prevents attackers from accessing files outside the intended directory.

Example

```python

import os

def secure_file_open(base_dir, filename):

"""Opens a file only if it exists within a specific directory."""

# Construct the full path

full_path = os.path.join(base_dir, filename)

# Normalize and verify path

if os.path.commonpath([os.path.abspath(full_path), base_dir]) != base_dir:

raise ValueError("Attempted directory traversal detected.")

try:

with open(full_path, 'r') as file:

return file.read()

except FileNotFoundError:

print("File not found.")

except Exception as e:

print(f"Error reading file: {e}")

# Usage

Explanation

Path Normalization: `os.path.commonpath` ensures that the resolved path (`full_path`) is within
`base_dir`, preventing attackers from accessing directories outside of `base_dir`.

Directory Traversal Protection: This approach prevents attacks where a user might try to access
unauthorized directories using `../`.

3. Avoid Storing Sensitive Data in Plain Text

When handling sensitive data, avoid writing it to disk in plain text. Encrypt data before writing it to a
file to prevent unauthorized access, even if the file is accessed directly.

Example (Using the `cryptography` library)

python
from cryptography.fernet import Fernet

import os

def encrypt_and_store_data(file_path, data, key):

"""Encrypts sensitive data and stores it in a file."""

fernet = Fernet(key)

encrypted_data = fernet.encrypt(data.encode())

with open(file_path, 'wb') as file:

file.write(encrypted_data)

os.chmod(file_path, 0o600) # Restrict permissions

def load_and_decrypt_data(file_path, key):

"""Loads and decrypts data from a file."""

fernet = Fernet(key)

with open(file_path, 'rb') as file:

encrypted_data = file.read()

return fernet.decrypt(encrypted_data).decode()

# Generate a secure key (store this key securely, e.g., in an environment variable)

key = Fernet.generate_key()

# Encrypt and store sensitive data

encrypt_and_store_data("secure_data.txt", "Sensitive information", key)

# Load and decrypt the data

print(load_and_decrypt_data("secure_data.txt", key))

Explanation

Encryption Before Storage: Encrypting data before storage ensures sensitive data remains
unreadable even if an unauthorized user accesses the file.

Secure Key Management: Use a secure, random key (such as one stored in an environment variable)
to handle encryption and decryption.

4. Implement Exception Handling and Error Logging

When dealing with file operations, implement proper exception handling to prevent crashes and
limit the information exposed in error messages.
Example

python

import logging

# Configure logging securely

logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(message)s')

def read_file_securely(file_path):

"""Reads a file securely with proper exception handling."""

try:

with open(file_path, 'r') as file:

return file.read()

except FileNotFoundError:

logging.warning(f"File not found: {file_path}")

except PermissionError:

logging.warning(f"Permission denied: {file_path}")

except Exception as e:

logging.error(f"Unexpected error: {e}")

# Usage

content = read_file_securely("sensitive_data.txt")

if content:

print("File content:", content)

Explanation

Detailed Error Logging: Logs warnings for common issues (like file not found or permission errors)
and logs critical errors if an unexpected issue arises.

Secure Logging Practices: Use logging instead of printing errors to the console, which can expose
sensitive file paths and internal details.

5. Use Temporary Files for Sensitive Data

For temporary storage of sensitive data, use Python’s `tempfile` module, which creates secure
temporary files that are automatically removed when closed.

Example
python

import tempfile

def secure_temp_file(data):

"""Stores data in a secure temporary file."""

try:

with tempfile.NamedTemporaryFile(delete=True) as temp_file:

temp_file.write(data.encode())

temp_file.flush() # Ensure data is written

print("Temporary file path:", temp_file.name)

# Read the data back

temp_file.seek(0)

print("Data in temp file:", temp_file.read().decode())

except Exception as e:

print(f"Error with temporary file: {e}")

# Usage

secure_temp_file("Sensitive temporary data"

Explanation

Automatic Cleanup: `tempfile.NamedTemporaryFile(delete=True)` ensures the temporary file is


deleted automatically after closing.

Isolation in Temporary Files: Temporary files are typically created in system-designated temp
directories, which are isolated and more secure.

---

6. Avoid Hardcoding File Paths and Sensitive Information

Avoid hardcoding sensitive information (like API keys, database credentials) or file paths in the code.
Instead, use environment variables or configuration files with restricted permissions.

Example

python
import os

def get_config_value(key):

"""Retrieves a configuration value from environment variables."""

value = os.getenv(key)

if not value:

raise EnvironmentError(f"Environment variable {key} not found.")

return value

# Usage: Store sensitive data in environment variables

api_key = get_config_value("API_KEY")

print("API Key retrieved securely.")

Explanation

Environment Variables: Use `os.getenv` to retrieve sensitive information, ensuring it’s not hard-
coded and is stored securely.

Secure Error Handling: Raises an exception if the required environment variable is missing,
preventing the application from running in an insecure state.

7. Clear Sensitive Data in Memory After Use

When handling sensitive information, explicitly clear or overwrite variables after use to prevent
residual data in memory. Python doesn't have built-in memory clearing, but you can manually
overwrite sensitive variables after use.

Example

```python

import tempfile

def handle_sensitive_data():

"""Demonstrates clearing sensitive data in memory."""

sensitive_data = "Sensitive data here"

# Write to a temporary file and clear after use

with tempfile.NamedTemporaryFile(delete=True) as temp_file:

temp_file.write(sensitive_data.encode())

temp_file.flush()

print("Data in temp file:", temp_file.read().decode())


Clear sensitive data

sensitive_data = None # Explicitly overwrite to clear it

Usage

handle_sensitive_data()

Explanation

Clearing Sensitive Variable: By setting `sensitive_data` to `None`, the reference is removed, helping
the garbage collector clear it from memory.

Safe Temporary Storage: Using `tempfile` for temporary data ensures it’s isolated and cleared after
the program exits or the temporary file is closed.

Summary of Secure File Handling Practices

1. Restrict Permissions: Set file permissions to limit access to sensitive files.

2. Validate Paths: Prevent path traversal by ensuring file paths stay within expected directories.

3. Encrypt Sensitive Data: Encrypt files containing sensitive information to protect against
unauthorized access.

4. Error Handling and Logging: Log errors securely and handle exceptions to prevent application
crashes.

5. Temporary Files: Use secure temporary files for transient data.

6. Environment Variables for Sensitive Info: Avoid hardcoding sensitive data; use environment
variables or secure config files.

7. Clear Data from Memory: Explicitly clear sensitive data from memory after use.

WEB REQUESTS :

Use HTTPS for Secure Connections

Always use HTTPS URLs to ensure that data is encrypted in transit. HTTPS encrypts data through
SSL/TLS, protecting it from interception by unauthorized parties.

Example

python
Copy code

import requests

def fetch_secure_data(url):

"""Fetches data only if the URL uses HTTPS."""

if not url.startswith("https://"):

raise ValueError("Insecure URL. Only HTTPS URLs are allowed.")

try:

response = requests.get(url)

response.raise_for_status() # Raise error for HTTP error codes

return response.json() # Assuming the response is in JSON format

except requests.exceptions.RequestException as e:

print(f"Request failed: {e}")

# Usage

data = fetch_secure_data("https://jsonplaceholder.typicode.com/todos/1")

print("Data:", data)

Explanation

HTTPS Requirement: By checking url.startswith("https://"), the function rejects insecure URLs (those
using HTTP).

Encrypted Communication: HTTPS secures data in transit, preventing it from being read by
unauthorized parties.

2. Enforce SSL Verification

By default, the requests library verifies SSL certificates, which is essential for preventing man-in-the-
middle attacks. If you need to disable SSL verification for testing, remember to re-enable it in
production.

Example

python

Copy code

def fetch_data_with_ssl_verification(url):
"""Fetches data with SSL verification enabled."""

try:

response = requests.get(url, verify=True)

response.raise_for_status()

return response.json()

except requests.exceptions.SSLError:

print("SSL verification failed.")

except requests.exceptions.RequestException as e:

print(f"Request error: {e}")

# Usage

fetch_data_with_ssl_verification("https://jsonplaceholder.typicode.com/todos/1")

Explanation

SSL Verification: The verify=True parameter ensures the SSL certificate is validated, which is
important for preventing connections to untrusted sources.

Error Handling: The code catches SSLError separately, providing a clear message when SSL
verification fails.

3. Set Timeouts to Prevent DoS Risks

Setting a timeout for HTTP requests limits the amount of time your application will wait for a
response, reducing the risk of Denial of Service (DoS) attacks due to hanging requests.

Example

python

Copy code

def fetch_data_with_timeout(url, timeout=5):

"""Fetches data with a specified timeout."""

try:

response = requests.get(url, timeout=timeout)

response.raise_for_status()

return response.json()

except requests.exceptions.Timeout:

print("Request timed out.")


except requests.exceptions.RequestException as e:

print(f"Request failed: {e}")

# Usage

fetch_data_with_timeout("https://jsonplaceholder.typicode.com/todos/1", timeout=3)

Explanation

Timeout Parameter: timeout=5 specifies the maximum wait time for the response. Adjust the
timeout based on your needs to balance responsiveness and reliability.

Protection Against DoS Attacks: Limiting the wait time prevents hanging requests, which can drain
resources.

4. Sanitize and Validate URLs

Avoid blindly using user-provided URLs in web requests. Instead, sanitize and validate URLs to
prevent SSRF (Server-Side Request Forgery) attacks, which could allow attackers to access internal
resources or sensitive information.

Example

python

Copy code

from urllib.parse import urlparse

def validate_url(url):

"""Validates if a URL is safe to use."""

parsed_url = urlparse(url)

if parsed_url.scheme != "https":

raise ValueError("Only HTTPS URLs are allowed.")

if not parsed_url.netloc:

raise ValueError("Invalid URL.")

def fetch_validated_data(url):

"""Fetches data from a validated URL."""

validate_url(url)

try:
response = requests.get(url, timeout=5)

response.raise_for_status()

return response.json()

except requests.exceptions.RequestException as e:

print(f"Request error: {e}")

# Usage

fetch_validated_data("https://jsonplaceholder.typicode.com/todos/1")

Explanation

URL Parsing and Validation: Using urlparse, the code checks that the URL has a scheme (https) and a
valid network location (netloc).

Protection Against SSRF: By validating URLs, you can restrict access to only secure, externally
accessible resources.

5. Use Headers Securely

HTTP headers can be manipulated to enhance security. For instance, setting a User-Agent header
can help identify your application, and setting Accept to specific formats limits the types of
responses your application handles.

Example

python

Copy code

def fetch_with_custom_headers(url):

"""Fetches data with custom headers."""

headers = {

"User-Agent": "MySecureApp/1.0",

"Accept": "application/json"

try:

response = requests.get(url, headers=headers, timeout=5)

response.raise_for_status()

return response.json()
except requests.exceptions.RequestException as e:

print(f"Request error: {e}")

# Usage

fetch_with_custom_headers("https://jsonplaceholder.typicode.com/todos/1")

Explanation

User-Agent: Identifying the application in headers is a good practice, as it helps servers recognize
requests from your specific app.

Accept Header: Specifying the response format, such as JSON, ensures your application processes
only expected formats, reducing the risk of handling untrusted data types.

6. Limit Redirects

Limit the number of redirects the request will follow to avoid open redirect vulnerabilities and
unintended redirects, which could send the application to untrusted sources.

Example

python

Copy code

def fetch_data_with_redirect_limit(url, max_redirects=3):

"""Fetches data with a limit on the number of redirects."""

try:

response = requests.get(url, timeout=5, allow_redirects=True)

response.history = response.history[:max_redirects] # Limit redirects

response.raise_for_status()

return response.json()

except requests.exceptions.TooManyRedirects:

print("Too many redirects.")

except requests.exceptions.RequestException as e:

print(f"Request error: {e}")

# Usage

fetch_data_with_redirect_limit("https://example.com")

Explanation
Limit on Redirects: This example restricts the number of redirects a request can follow, mitigating
the risk of open redirects.

Controlled Redirect Behavior: Reducing redirects ensures that the request only follows trusted
redirects, preventing unwanted redirection loops or redirects to malicious sites.

7. Validate Response Data

After receiving a response, validate and sanitize the data before processing it. This is especially
important if your application interacts with user-generated data, to avoid injecting malicious
content.

Example

python

Copy code

import json

def fetch_and_validate_json(url):

"""Fetches and validates JSON data."""

try:

response = requests.get(url, timeout=5)

response.raise_for_status()

# Ensure the response is JSON

if response.headers["Content-Type"] != "application/json":

raise ValueError("Unexpected content type.")

data = response.json()

# Example validation: check required fields

if "id" not in data or "title" not in data:

raise ValueError("Invalid JSON structure.")

return data

except json.JSONDecodeError:
print("Failed to parse JSON.")

except requests.exceptions.RequestException as e:

print(f"Request error: {e}")

# Usage

fetch_and_validate_json("https://jsonplaceholder.typicode.com/todos/1")

Explanation

Content Type Verification: By checking the Content-Type header, the function ensures the server
returned JSON data, avoiding unintended content types like HTML or XML.

JSON Validation: Additional checks confirm that expected fields are present, which helps prevent
data integrity issues and guards against maliciously crafted responses.

8. Handle Sensitive Data Carefully

When sending sensitive data in HTTP requests (such as API keys or passwords), use headers or a
secure payload rather than putting them in the URL. For extra security, use environment variables to
manage sensitive credentials.

Example

python

Copy code

import os

def fetch_data_with_auth(url):

"""Fetches data using secure authentication headers."""

api_key = os.getenv("API_KEY")

if not api_key:

raise EnvironmentError("API_KEY environment variable is missing.")

headers = {

"Authorization": f"Bearer {api_key}",

"User-Agent": "MySecureApp/1.0",

"Accept": "application/json"

}
try:

response = requests.get(url, headers=headers, timeout=5)

response.raise_for_status()

return response.json()

except requests.exceptions.RequestException as e:

print(f"Request error: {e}")

# Usage

fetch_data_with_auth("https://jsonplaceholder.typicode.com/todos/1")

You might also like