import hmac import hashlib import os # For simulating a secret key def verify_webhook_signature(payload_body, signature_header, secret_key): """Verifies the HMAC-SHA256 signature of a webhook payload. Args: payload_body (str): The raw request body as a string. signature_header (str): The signature value from the request header (e.g., 'X-Hub-Signature'). secret_key (str): The secret key shared between your application and the webhook sender. Returns: bool: True if the signature is valid, False otherwise. """ if not signature_header or not payload_body or not secret_key: return False # Example: 'sha256=abcdef1234567890...' -> extract 'abcdef1234567890...' # Adjust parsing based on the specific API's signature header format. try: algorithm, signature = signature_header.split('=', 1) except ValueError: return False # Invalid signature format if algorithm != 'sha256': # Or other expected algorithm like 'sha1' return False # Compute the HMAC digest expected_signature = hmac.new( secret_key.encode('utf-8'), payload_body.encode('utf-8'), hashlib.sha256 ).hexdigest() # Use hmac.compare_digest for constant-time comparison to prevent timing attacks return hmac.compare_digest(expected_signature, signature) # Usage example (in a Flask/Django/FastAPI route): # @app.route('/webhook', methods=['POST']) # def handle_webhook(): # secret = os.getenv('WEBHOOK_SECRET', 'my_super_secret_key') # Use environment variables for secrets # payload = request.get_data(as_text=True) # signature = request.headers.get('X-Hub-Signature-256') # Adjust header name as needed # # if verify_webhook_signature(payload, signature, secret): # print('Webhook signature verified successfully!') # # Process webhook event # return 'OK', 200 # else: # print('Webhook signature verification failed!') # return 'Unauthorized', 403