Is There a Sample Script for Hash Verification?

To verify the integrity of your exported Spirion logs, you can use a Python script that generates a SHA-256 hash of the log file immediately after export and compares it against a previously stored "known-good" hash.

Sample Python Script for Hash Generation and Verification

This sample Python script performs two functions:

  1. Generate: Creates a hash for a new export.
  2. Verify: Checks an existing file against a stored hash to detect tampering.
import hashlib
import os

# --- CONFIGURATION ---
LOG_FILE = "spirion_audit_export.json"
HASH_STORE = "log_integrity_hashes.txt"

def calculate_sha256(file_path):
"""Calculates the SHA-256 hash of a file in chunks to save memory."""
sha256_hash = hashlib.sha256()
try:
with open(file_path, "rb") as f:
# Read file in 4KB chunks
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
except FileNotFoundError:
return None

def record_new_hash(file_path):
"""Calculates and saves the hash for a new log export."""
file_hash = calculate_sha256(file_path)
if file_hash:
with open(HASH_STORE, "a") as f:
# Store filename and hash (standard sha256sum format)
f.write(f"{file_hash} {file_path}\n")
print(f"Integrity record created for {file_path}")
print(f"Hash: {file_hash}")
else:
print(f"Error: File {file_path} not found.")

def verify_integrity(file_path):
"""Compares current file hash against the last recorded hash."""
current_hash = calculate_sha256(file_path)
if not current_hash:
print(f"Error: File {file_path} not found.")
return False

try:
with open(HASH_STORE, "r") as f:
lines = f.readlines()
# Find the last entry for this specific file
matching_hashes = [l for l in lines if file_path in l]
if not matching_hashes:
print(f"No integrity record found for {file_path}.")
return False

last_recorded_hash = matching_hashes[-1].split()[0]

if current_hash == last_recorded_hash:
print(f"VERIFICATION SUCCESS: {file_path} integrity is intact.")
return True
else:
print(f"!!! VERIFICATION FAILURE !!!")
print(f"Expected: {last_recorded_hash}")
print(f"Actual: {current_hash}")
print(f"The file may have been tampered with or corrupted.")
return False
except FileNotFoundError:
print(f"Error: Hash store {HASH_STORE} not found.")
return False

if __name__ == "__main__":
# Example Workflow:
# 1. After your API export script runs, record the hash:
# record_new_hash(LOG_FILE)

# 2. Before your SIEM ingests or during an audit, verify it:
verify_integrity(LOG_FILE)

How to Operationalize This

  1. Post-Export Hook: Add the record_new_hash() function to the end of your Spirion API export script. This ensures every new file is "signed" immediately.
  2. Pre-Ingestion Check: Run verify_integrity() before your SIEM (like Splunk or Sentinel) pulls the data. If it fails, stop the ingestion and trigger a security alert.
  3. Secure the Hash Store: The log_integrity_hashes.txt file is your "Source of Truth." It must be stored on a different volume or server than the log files themselves to prevent an attacker from modifying both the log and the hash.

Recommendations

  • Use JSONL for Granularity: If you use JSON Lines (one event per line), you can technically hash each individual line and include the hash as a field in the JSON object. This allows you to detect if a single event was deleted from the middle of a large file.
  • Salt Your Hashes: For high-security environments, add a "secret salt" (a random string) to the hash calculation. This prevents an attacker from simply re-calculating a valid hash if they modify the log file.
  • Automate Alerts: If verify_integrity() returns False, have your script send an automated email or create a high-priority ticket in ServiceNow. A failed integrity check is a strong indicator of unauthorized administrative activity.

Summary

This script provides a simple but powerful way to ensure your Spirion log exports remain untampered.

By combining SHA-256 hashing with a secure hash store, you can provide auditors with mathematical proof that your sensitive data logs are accurate and complete.

Follow up: Is it Possible to Add Salting to the Hash Script?

Adding a salt to your hashing process significantly increases security by ensuring that an attacker cannot simply re-calculate a valid hash if they modify the log file. Even if they know you are using SHA-256, they would also need to know your "secret salt" to produce a matching hash.

Python Script for Hash Generation and Verification with Salting

In this version, we combine the file's content with a secret string before generating the final hash.

import hashlib
import os
# --- CONFIGURATION ---
LOG_FILE = "spirion_audit_export.json"
HASH_STORE = "log_integrity_hashes.txt"
# SECRET_SALT should be stored in a secure environment variable or vault.
# Never hardcode this in a production script.
SECRET_SALT = os.getenv("SPIRION_LOG_SALT", "YourSuperSecretSaltString123!")
def calculate_salted_sha256(file_path, salt):
"""Calculates a salted SHA-256 hash of a file."""
sha256_hash = hashlib.sha256()
# 1. Start the hash with the secret salt
sha256_hash.update(salt.encode('utf-8'))
try:
with open(file_path, "rb") as f:
# 2. Update the hash with the file content in chunks
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
# 3. Optional: Update the hash with the salt again at the end (Double Salting)
sha256_hash.update(salt.encode('utf-8'))
return sha256_hash.hexdigest()
except FileNotFoundError:
return None
def record_salted_hash(file_path):
"""Calculates and saves the salted hash for a new log export."""
file_hash = calculate_salted_sha256(file_path, SECRET_SALT)
if file_hash:
with open(HASH_STORE, "a") as f:
f.write(f"{file_hash} {file_path}\n")
print(f"Salted integrity record created for {file_path}")
else:
print(f"Error: File {file_path} not found.")
def verify_salted_integrity(file_path):
"""Verifies the file against the stored salted hash."""
current_hash = calculate_salted_sha256(file_path, SECRET_SALT)
if not current_hash:
return False
try:
with open(HASH_STORE, "r") as f:
lines = f.readlines()
matching_hashes = [l for l in lines if file_path in l]
if not matching_hashes:
print(f"No record found for {file_path}.")
return False
last_recorded_hash = matching_hashes[-1].split()[0]
if current_hash == last_recorded_hash:
print(f"SUCCESS: Salted integrity intact for {file_path}.")
return True
else:
print(f"!!! ALERT: Salted integrity check FAILED for {file_path} !!!")
return False
except FileNotFoundError:
print(f"Error: Hash store {HASH_STORE} not found.")
return False
if __name__ == "__main__":
# record_salted_hash(LOG_FILE)
verify_salted_integrity(LOG_FILE)

Why Salting Matters for Spirion Logs

  1. Prevents "Pre-Computed" Attacks: An attacker cannot use a "Rainbow Table" (a list of pre-calculated hashes for common log patterns) to guess your log content.
  2. Authentication of the Exporter: Because only your export script and your verification script know the SECRET_SALT, the hash acts as a simple Message Authentication Code (MAC). It proves the file was generated by your script and not an external actor.
  3. Protection Against "Hash Swapping": If an attacker modifies the log file, they cannot simply run sha256sum on the new file and update your HASH_STORE because they don't have the salt required to generate the correct hash.

Best Practices for Salting

  • Environment Variables: As shown in the script, use os.getenv("SPIRION_LOG_SALT"). This keeps the salt out of your source code repository (Git/Bitbucket).
  • Salt Length: Use a salt that is at least 16–32 characters long and includes a mix of letters, numbers, and symbols.
  • Unique Salts per Environment: Use a different salt for your Production, Staging, and Dev environments. This ensures that a compromise in a lower environment doesn't affect your production log integrity.
  • Rotate the Salt: If you suspect your export server has been compromised, rotate the salt immediately. Note that this will make all previous hashes in your HASH_STORE invalid for verification, so keep a record of old salts if you need to verify historical logs.

Summary

Adding a salt to your hashing script transforms a simple integrity check into a robust security control. It ensures that your Spirion log exports are not only unchanged but also authenticated as coming from your trusted export process.