Get a Pentest and security assessment of your IT network.

Cyber Security

Web Service Authentication

TL;DR

Secure communication between web services within your project using API keys and a shared secret. This guide shows you how to generate, store, and verify these keys for robust authentication.

Generating API Keys

  1. Choose a Key Generation Method: Use a cryptographically secure random string generator. Avoid simple sequential IDs.
    python
    import secrets
    import string
    
    def generate_api_key(length=32):
      alphabet = string.ascii_letters + string.digits
      return ''.join(secrets.choice(alphabet) for i in range(length))
    
    api_key = generate_api_key()
    print(api_key)
    
  2. Store the Shared Secret: Keep a strong, randomly generated secret key securely on your server. This is used to sign and verify API requests. Do not hardcode it into your application! Environment variables or a dedicated secrets management system are best.
    # Example using environment variable
    SHARED_SECRET = os.environ.get('API_SHARED_SECRET')
    
  3. Associate Keys with Services: Link each generated API key to the specific web service that owns it. Store this mapping in your database.

    Example Database Table:

    • api_key (VARCHAR) - Primary Key
    • service_name (VARCHAR)
    • created_at (TIMESTAMP)

Authentication Process

  1. Request Signing: When a web service makes a request to another, it includes the API key and a signature. The signature is created using the shared secret and the request data.
    import hmac
    import hashlib
    import time
    
    def create_signature(api_key, shared_secret, timestamp):
      message = f'{api_key}{timestamp}'.encode('utf-8')
      signature = hmac.new(shared_secret.encode('utf-8'), message, hashlib.sha256).hexdigest()
      return signature
    
    # Example usage:
    timestamp = str(int(time.time()))
    signature = create_signature("your_api_key", "your_shared_secret", timestamp)
    print(f"Signature: {signature}")
    
  2. Include Signature in Request: Add the API key and signature as headers to your HTTP request.

    Example Headers:

    • X-API-Key: your_api_key
    • X-API-Timestamp: timestamp
    • X-API-Signature: signature
  3. Verification on Receiving Service: The receiving web service verifies the signature using its copy of the shared secret.
    def verify_signature(api_key, shared_secret, timestamp, signature):
      expected_signature = create_signature(api_key, shared_secret, timestamp)
      return hmac.compare_digest(signature, expected_signature) # Use compare_digest for security
    
  4. Check Key Existence: Before verifying the signature, confirm that the API key exists in your database and is associated with the calling service.

    This prevents unauthorized access even if a valid signature is provided.

Security Considerations

  • HTTPS: Always use HTTPS to encrypt communication between services.
  • Timestamp Expiration: Limit the validity of timestamps (e.g., requests older than 5 minutes are rejected) to prevent replay attacks.
  • Rate Limiting: Implement rate limiting to protect against abuse.
  • Shared Secret Rotation: Regularly rotate your shared secret to minimize the impact of a potential compromise.
  • Compare Digests: Use hmac.compare_digest() instead of direct string comparison for signature verification to prevent timing attacks.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation