1个不稳定版本
0.4.0 | 2019年4月13日 |
---|
#55 in #reverse-proxy
用于 spectacles
11KB
117 行
hyper-reverse-proxy
一个简单的反向代理,与Hyper一起使用。
实现确保在两个方向上正确删除端到端头部,并在X-Forwarded-For
头部中添加客户端IP地址到逗号分隔的转发地址列表。
实现基于Go的httputil.ReverseProxy
。
示例
将这些依赖项添加到您的Cargo.toml
文件中。
[dependencies]
hyper-reverse-proxy = "?"
hyper = { version = "?", features = ["full"] }
tokio = { version = "?", features = ["full"] }
lazy_static = "?"
hyper-trust-dns = { version = "?", features = [
"rustls-http2",
"dnssec-ring",
"dns-over-https-rustls",
"rustls-webpki",
"https-only"
] }
以下示例将在127.0.0.1:13900
上设置反向代理,并将这些调用代理
-
"/target/first"
将被代理到http://127.0.0.1:13901
-
"/target/second"
将被代理到http://127.0.0.1:13902
-
所有其他URL将由
debug_request
函数处理,该函数将显示请求信息。
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server, StatusCode};
use hyper_reverse_proxy::ReverseProxy;
use hyper_trust_dns::{RustlsHttpsConnector, TrustDnsResolver};
use std::net::IpAddr;
use std::{convert::Infallible, net::SocketAddr};
lazy_static::lazy_static! {
static ref PROXY_CLIENT: ReverseProxy<RustlsHttpsConnector> = {
ReverseProxy::new(
hyper::Client::builder().build::<_, hyper::Body>(TrustDnsResolver::default().into_rustls_webpki_https_connector()),
)
};
}
fn debug_request(req: &Request<Body>) -> Result<Response<Body>, Infallible> {
let body_str = format!("{:?}", req);
Ok(Response::new(Body::from(body_str)))
}
async fn handle(client_ip: IpAddr, req: Request<Body>) -> Result<Response<Body>, Infallible> {
if req.uri().path().starts_with("/target/first") {
match PROXY_CLIENT.call(client_ip, "http://127.0.0.1:13901", req)
.await
{
Ok(response) => {
Ok(response)
},
Err(_error) => {
Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())},
}
} else if req.uri().path().starts_with("/target/second") {
match PROXY_CLIENT.call(client_ip, "http://127.0.0.1:13902", req)
.await
{
Ok(response) => Ok(response),
Err(_error) => Ok(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap()),
}
} else {
debug_request(&req)
}
}
#[tokio::main]
async fn main() {
let bind_addr = "127.0.0.1:8000";
let addr: SocketAddr = bind_addr.parse().expect("Could not parse ip:port.");
let make_svc = make_service_fn(|conn: &AddrStream| {
let remote_addr = conn.remote_addr().ip();
async move { Ok::<_, Infallible>(service_fn(move |req| handle(remote_addr, req))) }
});
let server = Server::bind(&addr).serve(make_svc);
println!("Running server on {:?}", addr);
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}
关于安全性的话
处理发出的请求可能是一个安全噩梦。这个crate不控制发出的请求客户端,因为它需要提供给代理调用。以下章节可能会给您一个关于如何使用hyper-trust-dns
crate来保护您的客户端的概述。
您可以在示例中看到它们的使用。
HTTPS
您应该使用安全传输,以便知道您在跟谁说话,并且可以信任连接。默认情况下,hyper-trust-dns
启用了功能标志https-only
,如果提供的是不是https
的传输方案,则会引发恐慌。这是一个健康的默认值,因为它不仅需要您信任来源,还需要其他人信任在未加密连接上看到的内容。
注意:如果您正在运行主机,其中证书存储中添加了证书,请确保定期审计它们,以确保您的客户端不会将旧证书或恶意证书视为有效。
TLS 1.2
默认情况下,禁用了 tls 1.2
,以启用 tls 1.3
,因为许多 tls 1.2
的部分可能被视为攻击友好。由于并非所有服务都支持它,可以通过 rustls-tls-12
功能启用 tls 1.2
。
注意:请确保定期审计您连接到的服务
DNSSEC
从安全角度来看,默认情况下,DNS查询和条目不是“可信”的。 DNSSEC
为验证添加了一个新的加密层。要启用它,请使用 dnssec-ring
功能。
HTTP/2
默认情况下,只启用了 rustlss 的 http1
功能以用于 DNS 查询。虽然 http/3
可能就在眼前。可以通过 rustls-http2
功能启用 http/2
支持。
DoT & DoH
DoT 和 DoH 为您提供与 DNS 之间的安全传输。
默认情况下,它们都不启用。如果您想启用它们,可以使用 doh
和 dot
功能。
建议
- 如果您需要监控与访问端口相关的网络活动,请使用具有
dns-over-rustls
功能标志的 DoT。 - 如果您在野外并且没有根据端口监控的需求,请使用具有
dns-over-https-rustls
功能标志的 DoH,因为它将与其他https
流量混合。
强烈建议使用其中之一。
目前仅包括 DNS 查询作为
esni
或ech
仍在ietf
中为草案的原因。
依赖关系
~7–17MB
~220K SLoC