From feeaf42e218c665ab7c38a7f2b3858f94f1b4ee0 Mon Sep 17 00:00:00 2001 From: onlyyu1996 <1158673577@qq.com> Date: Mon, 18 May 2026 14:05:48 +0800 Subject: [PATCH] fix(app-server): restrict proxy ports --- src/cortex-app-server/src/api/proxy.rs | 48 +++++++++++++++++++++----- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/cortex-app-server/src/api/proxy.rs b/src/cortex-app-server/src/api/proxy.rs index d5b68057f..8a30133a4 100644 --- a/src/cortex-app-server/src/api/proxy.rs +++ b/src/cortex-app-server/src/api/proxy.rs @@ -4,20 +4,20 @@ use axum::{Json, extract::Path}; use crate::error::{AppError, AppResult}; +const ALLOWED_PROXY_PORTS: &[u16] = &[ + 3000, 3001, 3002, 3003, // React、Next.js + 4000, 4173, 4200, // Angular、Vite 预览 + 5000, 5173, 5174, // Vite、Flask + 8000, 8080, 8081, // Django、通用开发服务 +]; + /// List open ports on localhost. pub async fn list_open_ports() -> Json> { - let ports_to_check: Vec = vec![ - 3000, 3001, 3002, 3003, // React, Next.js - 4000, 4173, 4200, // Angular, Vite preview - 5000, 5173, 5174, // Vite, Flask - 8000, 8080, 8081, // Django, generic - ]; - let mut open_ports = Vec::new(); - for port in ports_to_check { + for port in ALLOWED_PROXY_PORTS { if std::net::TcpStream::connect(format!("127.0.0.1:{port}")).is_ok() { - open_ports.push(port); + open_ports.push(*port); } } @@ -36,6 +36,12 @@ pub async fn proxy_to_port_path( use axum::body::Body; use axum::http::{StatusCode, header}; + if !is_proxy_port_allowed(port) { + return Err(AppError::Authorization(format!( + "Port {port} is not allowed for proxying" + ))); + } + let target_url = format!("http://127.0.0.1:{port}/{path}"); let client = reqwest::Client::builder() @@ -79,3 +85,27 @@ pub async fn proxy_to_port_path( .body(Body::from(body)) .map_err(|e| AppError::Internal(format!("Failed to build response: {e}"))) } + +fn is_proxy_port_allowed(port: u16) -> bool { + ALLOWED_PROXY_PORTS.contains(&port) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn proxy_rejects_non_dev_ports() { + let result = proxy_to_port_path(Path((22, String::new()))).await; + + assert!(matches!(result, Err(AppError::Authorization(_)))); + } + + #[test] + fn proxy_allows_only_known_dev_ports() { + assert!(is_proxy_port_allowed(5173)); + assert!(is_proxy_port_allowed(8080)); + assert!(!is_proxy_port_allowed(22)); + assert!(!is_proxy_port_allowed(9200)); + } +}