mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-25 18:54:30 +00:00
security - check max request size
This commit is contained in:
parent
05ba34b9b7
commit
4ab8d2229d
3 changed files with 89 additions and 12 deletions
|
@ -1,5 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from fastapi import Request
|
||||||
|
|
||||||
from litellm._logging import verbose_proxy_logger
|
from litellm._logging import verbose_proxy_logger
|
||||||
from litellm.proxy._types import *
|
from litellm.proxy._types import *
|
||||||
|
|
||||||
|
@ -75,3 +77,69 @@ def is_llm_api_route(route: str) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
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)
|
||||||
|
|
|
@ -57,6 +57,7 @@ from litellm.proxy.auth.auth_checks import (
|
||||||
log_to_opentelemetry,
|
log_to_opentelemetry,
|
||||||
)
|
)
|
||||||
from litellm.proxy.auth.auth_utils import (
|
from litellm.proxy.auth.auth_utils import (
|
||||||
|
check_if_request_size_is_safe,
|
||||||
is_llm_api_route,
|
is_llm_api_route,
|
||||||
route_in_additonal_public_routes,
|
route_in_additonal_public_routes,
|
||||||
)
|
)
|
||||||
|
@ -116,6 +117,21 @@ async def user_api_key_auth(
|
||||||
try:
|
try:
|
||||||
route: str = request.url.path
|
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: Optional[List[dict]] = general_settings.get(
|
||||||
"pass_through_endpoints", None
|
"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 (
|
if (
|
||||||
route in LiteLLMRoutes.public_routes.value
|
route in LiteLLMRoutes.public_routes.value
|
||||||
or route_in_additonal_public_routes(current_route=route)
|
or route_in_additonal_public_routes(current_route=route)
|
||||||
|
|
|
@ -34,5 +34,10 @@ general_settings:
|
||||||
"llm_requests_hanging": "https://hooks.slack.com/services/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",
|
"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:
|
litellm_settings:
|
||||||
success_callback: ["langfuse"]
|
success_callback: ["langfuse"]
|
Loading…
Add table
Add a link
Reference in a new issue