Skip to content

Commit feeaf42

Browse files
committed
fix(app-server): restrict proxy ports
1 parent 7954d02 commit feeaf42

1 file changed

Lines changed: 39 additions & 9 deletions

File tree

src/cortex-app-server/src/api/proxy.rs

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@ use axum::{Json, extract::Path};
44

55
use crate::error::{AppError, AppResult};
66

7+
const ALLOWED_PROXY_PORTS: &[u16] = &[
8+
3000, 3001, 3002, 3003, // React、Next.js
9+
4000, 4173, 4200, // Angular、Vite 预览
10+
5000, 5173, 5174, // Vite、Flask
11+
8000, 8080, 8081, // Django、通用开发服务
12+
];
13+
714
/// List open ports on localhost.
815
pub async fn list_open_ports() -> Json<Vec<u16>> {
9-
let ports_to_check: Vec<u16> = vec![
10-
3000, 3001, 3002, 3003, // React, Next.js
11-
4000, 4173, 4200, // Angular, Vite preview
12-
5000, 5173, 5174, // Vite, Flask
13-
8000, 8080, 8081, // Django, generic
14-
];
15-
1616
let mut open_ports = Vec::new();
1717

18-
for port in ports_to_check {
18+
for port in ALLOWED_PROXY_PORTS {
1919
if std::net::TcpStream::connect(format!("127.0.0.1:{port}")).is_ok() {
20-
open_ports.push(port);
20+
open_ports.push(*port);
2121
}
2222
}
2323

@@ -36,6 +36,12 @@ pub async fn proxy_to_port_path(
3636
use axum::body::Body;
3737
use axum::http::{StatusCode, header};
3838

39+
if !is_proxy_port_allowed(port) {
40+
return Err(AppError::Authorization(format!(
41+
"Port {port} is not allowed for proxying"
42+
)));
43+
}
44+
3945
let target_url = format!("http://127.0.0.1:{port}/{path}");
4046

4147
let client = reqwest::Client::builder()
@@ -79,3 +85,27 @@ pub async fn proxy_to_port_path(
7985
.body(Body::from(body))
8086
.map_err(|e| AppError::Internal(format!("Failed to build response: {e}")))
8187
}
88+
89+
fn is_proxy_port_allowed(port: u16) -> bool {
90+
ALLOWED_PROXY_PORTS.contains(&port)
91+
}
92+
93+
#[cfg(test)]
94+
mod tests {
95+
use super::*;
96+
97+
#[tokio::test]
98+
async fn proxy_rejects_non_dev_ports() {
99+
let result = proxy_to_port_path(Path((22, String::new()))).await;
100+
101+
assert!(matches!(result, Err(AppError::Authorization(_))));
102+
}
103+
104+
#[test]
105+
fn proxy_allows_only_known_dev_ports() {
106+
assert!(is_proxy_port_allowed(5173));
107+
assert!(is_proxy_port_allowed(8080));
108+
assert!(!is_proxy_port_allowed(22));
109+
assert!(!is_proxy_port_allowed(9200));
110+
}
111+
}

0 commit comments

Comments
 (0)