Blog | G5 Cyber Security

Secure Subrequests: Authentication & Authorization

TL;DR

This guide shows how to securely handle authentication and authorization when making subrequests (requests from your application to itself or other services). We’ll cover passing user information, verifying access rights, and protecting against common vulnerabilities.

1. Understanding the Problem

When your application makes a request to another part of itself (a subrequest), it doesn’t automatically inherit the original user’s identity or permissions. You need to explicitly pass this information along and verify it on the receiving end. Failing to do so can lead to security breaches where users gain access to resources they shouldn’t.

2. Passing User Information

  1. Headers: The most common approach is to include user-related data in HTTP headers.
  • Example (Python with Requests):
    import requests
    
    token = 'your_jwt_token'
    user_id = 123
    
    headers = {
        'Authorization': f'Bearer {token}',
        'X-User-ID': str(user_id)
    }
    
    response = requests.get('https://your-subrequest-endpoint', headers=headers)
    
  • Context Propagation: For more complex applications, consider using context propagation libraries (e.g., OpenTelemetry) to automatically pass tracing and user information across service boundaries.
  • 3. Verifying Access Rights

    1. Authentication Middleware: Implement middleware on the receiving end of the subrequest to authenticate the user based on the passed credentials (e.g., token validation).
  • Authorization Logic: After authentication, determine if the user has permission to access the requested resource or perform the desired action.
  • Example (Python with Flask):
    from flask import request, jsonify
    
    @app.route('/protected')
    def protected_resource():
        token = request.headers.get('Authorization')
        user_id = request.headers.get('X-User-ID')
    
        if not token or not user_id:
            return jsonify({'message': 'Authentication required'}), 401
    
        # Validate the token and retrieve user information...
        # (This is a simplified example; use a proper library)
        user = get_user(int(user_id))
    
        if not user or user.role != 'admin':
            return jsonify({'message': 'Authorization failed'}), 403
    
        return jsonify({'message': 'Access granted'}) 
    

    4. Security Considerations

    1. Never Trust Client Data: Always validate data received from the client (including headers) before using it.
    2. HTTPS Only: Ensure all communication between your application and subrequests is over HTTPS to prevent eavesdropping and man-in-the-middle attacks.
    3. Input Validation: Sanitize and validate any input passed in the request, even if it’s coming from a trusted source within your own application.
    4. Rate Limiting: Implement rate limiting on subrequests to prevent abuse and denial-of-service attacks.
    5. Logging & Auditing: Log all authentication and authorization events for auditing purposes.

    5. Common Mistakes

    • Skipping Authentication: Assuming that because it’s an internal request, no authentication is needed.
    • Hardcoding Permissions: Embedding permissions directly in the code instead of using a flexible RBAC or ABAC system.
    • Insufficient Validation: Failing to properly validate user input and credentials.
  • Exit mobile version