如何在Actix-web中无响应直接关闭连接以应对类DDoS请求
解决方案:在Actix Web中直接关闭连接不返回响应
要实现直接关闭连接、不向客户端发送任何响应的需求,你可以通过Actix Web的底层连接控制API来实现,核心是获取当前请求的底层HTTP连接并主动关闭,同时避免返回任何有效响应内容。
方法1:在路由处理函数中直接关闭连接
修改你的defaultentry函数,通过HttpRequest的扩展信息拿到底层连接并关闭,同时消费请求payload防止连接挂起:
use actix_web::{web, HttpRequest, HttpResponse, Error, http::StatusCode}; use actix_web::dev::HttpConnection; async fn defaultentry(req: HttpRequest, payload: web::Payload) -> Result<impl Responder, Error> { // 获取底层HTTP连接并执行关闭操作 if let Some(conn) = req.extensions().get::<HttpConnection>() { conn.close(); } // 消费请求payload,避免未处理的数据导致连接无法正常关闭 while let Some(_chunk) = payload.next().await {} // 返回空的无内容响应(实际客户端不会收到,因为连接已提前关闭) Ok(HttpResponse::new(StatusCode::NO_CONTENT).finish()) }
方法2:用中间件提前拦截恶意请求
如果需要在请求进入路由处理前就拦截并关闭连接,推荐用中间件实现,性能更高,能避免不必要的请求解析开销:
use actix_web::{ dev::{Service, ServiceRequest, ServiceResponse, Transform}, Error, HttpResponse, http::StatusCode, }; use futures::future::{ready, Ready}; use std::task::{Context, Poll}; // 定义中间件结构体 struct MaliciousRequestBlocker; impl<S, B> Transform<S, ServiceRequest> for MaliciousRequestBlocker where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse<B>; type Error = Error; type Transform = BlockerService<S>; type InitError = (); type Future = Ready<Result<Self::Transform, Self::InitError>>; fn new_transform(&self, service: S) -> Self::Future { ready(Ok(BlockerService { service })) } } // 中间件服务逻辑实现 struct BlockerService<S> { service: S, } impl<S, B> Service<ServiceRequest> for BlockerService<S> where S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse<B>; type Error = Error; type Future = Ready<Result<Self::Response, Self::Error>>; fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { self.service.poll_ready(cx) } fn call(&self, req: ServiceRequest) -> Self::Future { // 替换成你的恶意请求判断逻辑,比如IP黑名单、请求特征匹配等 let is_malicious = true; if is_malicious { // 关闭当前连接 if let Some(conn) = req.extensions().get::<actix_web::dev::HttpConnection>() { conn.close(); } // 返回空响应(连接已关闭,客户端不会收到任何内容) ready(Ok(req.into_response(HttpResponse::new(StatusCode::NO_CONTENT).finish()))) } else { // 正常转发请求到后续服务或路由 ready(self.service.call(req).await) } } }
然后在main函数中注册该中间件:
#[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(move || { App::new() .wrap(MaliciousRequestBlocker) // 注册恶意请求拦截中间件 .default_service(web::get().to(defaultentry)) }) .bind(("0.0.0.0", 8080))? .run() .await }
关键说明
- 直接关闭连接后,客户端会收到TCP连接断开/重置信号,不会获取到任何HTTP响应,以此迫使发起方的TIME-WAIT连接堆积。
- 消费请求payload是必要步骤,否则未处理的请求数据可能导致连接无法正常关闭。
- 中间件方式更适合批量拦截恶意请求,因为它在请求解析的早期阶段就介入,性能优于路由内处理。
内容的提问来源于stack exchange,提问作者Agathe_DVY
相关产品推荐
相关产品推荐

