mirror of
https://github.com/langgenius/dify.git
synced 2026-03-29 09:59:59 +08:00
add internal ip filter when parse tool schema
This commit is contained in:
@ -8,10 +8,11 @@ import httpx
|
||||
from flask import request
|
||||
from yaml import YAMLError, safe_load
|
||||
|
||||
from core.helper.ssrf_proxy import is_private_or_local_address
|
||||
from core.tools.entities.common_entities import I18nObject
|
||||
from core.tools.entities.tool_bundle import ApiToolBundle
|
||||
from core.tools.entities.tool_entities import ApiProviderSchemaType, ToolParameter
|
||||
from core.tools.errors import ToolApiSchemaError, ToolNotSupportedError, ToolProviderNotFoundError
|
||||
from core.tools.errors import ToolApiSchemaError, ToolNotSupportedError, ToolProviderNotFoundError, ToolSSRFError
|
||||
|
||||
|
||||
class ApiBasedToolSchemaParser:
|
||||
@ -28,6 +29,15 @@ class ApiBasedToolSchemaParser:
|
||||
if len(openapi["servers"]) == 0:
|
||||
raise ToolProviderNotFoundError("No server found in the openapi yaml.")
|
||||
|
||||
# SSRF Protection: Validate all server URLs before processing
|
||||
for server in openapi["servers"]:
|
||||
server_url_to_check = server.get("url", "")
|
||||
if server_url_to_check and is_private_or_local_address(server_url_to_check):
|
||||
raise ToolSSRFError(
|
||||
f"Server URL '{server_url_to_check}' points to a private or local network address, "
|
||||
"which is not allowed for security reasons (SSRF protection)."
|
||||
)
|
||||
|
||||
server_url = openapi["servers"][0]["url"]
|
||||
request_env = request.headers.get("X-Request-Env")
|
||||
if request_env:
|
||||
@ -287,6 +297,15 @@ class ApiBasedToolSchemaParser:
|
||||
if len(servers) == 0:
|
||||
raise ToolApiSchemaError("No server found in the swagger yaml.")
|
||||
|
||||
# SSRF Protection: Validate all server URLs before processing
|
||||
for server in servers:
|
||||
server_url_to_check = server.get("url", "")
|
||||
if server_url_to_check and is_private_or_local_address(server_url_to_check):
|
||||
raise ToolSSRFError(
|
||||
f"Server URL '{server_url_to_check}' points to a private or local network address, "
|
||||
"which is not allowed for security reasons (SSRF protection)."
|
||||
)
|
||||
|
||||
converted_openapi: dict[str, Any] = {
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
@ -360,6 +379,13 @@ class ApiBasedToolSchemaParser:
|
||||
if api_type != "openapi":
|
||||
raise ToolNotSupportedError("Only openapi is supported now.")
|
||||
|
||||
# SSRF Protection: Validate API URL before making HTTP request
|
||||
if is_private_or_local_address(api_url):
|
||||
raise ToolSSRFError(
|
||||
f"API URL '{api_url}' points to a private or local network address, "
|
||||
"which is not allowed for security reasons (SSRF protection)."
|
||||
)
|
||||
|
||||
# get openapi yaml
|
||||
response = httpx.get(
|
||||
api_url, headers={"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "}, timeout=5
|
||||
@ -424,8 +450,10 @@ class ApiBasedToolSchemaParser:
|
||||
return openapi, schema_type
|
||||
except ToolApiSchemaError as e:
|
||||
openapi_error = e
|
||||
except ToolSSRFError:
|
||||
raise
|
||||
|
||||
# openai parse error, fallback to swagger
|
||||
# openapi parse error, fallback to swagger
|
||||
try:
|
||||
converted_swagger = ApiBasedToolSchemaParser.parse_swagger_to_openapi(
|
||||
loaded_content, extra_info=extra_info, warning=warning
|
||||
@ -436,13 +464,18 @@ class ApiBasedToolSchemaParser:
|
||||
), schema_type
|
||||
except ToolApiSchemaError as e:
|
||||
swagger_error = e
|
||||
|
||||
except ToolSSRFError:
|
||||
# SSRF protection errors should be raised immediately, don't fallback
|
||||
raise
|
||||
# swagger parse error, fallback to openai plugin
|
||||
try:
|
||||
openapi_plugin = ApiBasedToolSchemaParser.parse_openai_plugin_json_to_tool_bundle(
|
||||
json_dumps(loaded_content), extra_info=extra_info, warning=warning
|
||||
)
|
||||
return openapi_plugin, ApiProviderSchemaType.OPENAI_PLUGIN
|
||||
except ToolSSRFError:
|
||||
# SSRF protection errors should be raised immediately, don't fallback
|
||||
raise
|
||||
except ToolNotSupportedError as e:
|
||||
# maybe it's not plugin at all
|
||||
openapi_plugin_error = e
|
||||
|
||||
Reference in New Issue
Block a user