From 4ab8d2229d23f362418ee93b1daf7d86543f1efe Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 27 Jul 2024 16:08:41 -0700 Subject: [PATCH] security - check max request size --- litellm/proxy/auth/auth_utils.py | 68 +++++++++++++++++++++++++ litellm/proxy/auth/user_api_key_auth.py | 28 +++++----- litellm/proxy/proxy_config.yaml | 5 ++ 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index bd1e50ed0b..83c676518d 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -1,5 +1,7 @@ import re +from fastapi import Request + from litellm._logging import verbose_proxy_logger from litellm.proxy._types import * @@ -75,3 +77,69 @@ def is_llm_api_route(route: str) -> bool: return True return False + + +async def check_if_request_size_is_safe(request: Request) -> bool: + """ + Enterprise Only: + - Checks if the request size is within the limit + + Args: + request (Request): The incoming request. + + Returns: + bool: True if the request size is within the limit, False otherwise. + """ + from litellm.proxy.proxy_server import general_settings, premium_user + + max_request_size_mb = general_settings.get("max_request_size_mb", None) + if max_request_size_mb is not None: + # Check if premium user + if premium_user is not True: + verbose_proxy_logger.warning( + f"using max_request_size_mb - not checking - this is an enterprise only feature. {CommonProxyErrors.not_premium_user.value}" + ) + return True + + # Get the request body + content_length = request.headers.get("content-length") + + if content_length: + header_size = int(content_length) + header_size_mb = bytes_to_mb(bytes_value=header_size) + verbose_proxy_logger.debug( + f"content_length request size in MB={header_size_mb}" + ) + + if header_size_mb > max_request_size_mb: + raise ProxyException( + message=f"Request size is too large. Request size is {header_size_mb} MB. Max size is {max_request_size_mb} MB", + type=ProxyErrorTypes.bad_request_error.value, + code=400, + param="content-length", + ) + else: + # If Content-Length is not available, read the body + body = await request.body() + body_size = len(body) + request_size_mb = bytes_to_mb(bytes_value=body_size) + + verbose_proxy_logger.debug( + f"request body request size in MB={request_size_mb}" + ) + if request_size_mb > max_request_size_mb: + raise ProxyException( + message=f"Request size is too large. Request size is {request_size_mb} MB. Max size is {max_request_size_mb} MB", + type=ProxyErrorTypes.bad_request_error.value, + code=400, + param="content-length", + ) + + return True + + +def bytes_to_mb(bytes_value: int): + """ + Helper to convert bytes to MB + """ + return bytes_value / (1024 * 1024) diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index d91baf5cad..8a1f97f4c3 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -57,6 +57,7 @@ from litellm.proxy.auth.auth_checks import ( log_to_opentelemetry, ) from litellm.proxy.auth.auth_utils import ( + check_if_request_size_is_safe, is_llm_api_route, route_in_additonal_public_routes, ) @@ -116,6 +117,21 @@ async def user_api_key_auth( try: route: str = request.url.path + ### LiteLLM Enterprise Security Checks + # Check 1. Check if request size is under max_request_size_mb + # Check 2. FILTER IP ADDRESS + await check_if_request_size_is_safe(request=request) + + is_valid_ip = _check_valid_ip( + allowed_ips=general_settings.get("allowed_ips", None), request=request + ) + + if not is_valid_ip: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Access forbidden: IP address not allowed.", + ) + pass_through_endpoints: Optional[List[dict]] = general_settings.get( "pass_through_endpoints", None ) @@ -170,18 +186,6 @@ async def user_api_key_auth( ``` """ - ### FILTER IP ADDRESS ### - - is_valid_ip = _check_valid_ip( - allowed_ips=general_settings.get("allowed_ips", None), request=request - ) - - if not is_valid_ip: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Access forbidden: IP address not allowed.", - ) - if ( route in LiteLLMRoutes.public_routes.value or route_in_additonal_public_routes(current_route=route) diff --git a/litellm/proxy/proxy_config.yaml b/litellm/proxy/proxy_config.yaml index 4df5103996..2fe8eb2a55 100644 --- a/litellm/proxy/proxy_config.yaml +++ b/litellm/proxy/proxy_config.yaml @@ -34,5 +34,10 @@ general_settings: "llm_requests_hanging": "https://hooks.slack.com/services/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", } + # Security controls + max_request_size_mb: 100 + # google cloud run maximum repsonses size is 32MB + max_response_size_mb: 100 + litellm_settings: success_callback: ["langfuse"] \ No newline at end of file