我可以在不向客户端发送响应的情况下终止服务器上的HTTP事务吗?

时间:2019-08-21 18:23:24

标签: c# asp.net http iis timeout

我正在编写面向公众的交易处理器。自然,我们在https://上运行,并且有效负载包含所有相关细节,因此我们将仅处理合法交易。但是,作为公共接口,任何其他邪恶的行为者毫无疑问都将在我的服务器上蒙上阴影,除非是因为烦人而已。

当我检测到这样的请求时,是否有可以终止的处理-不会在事务上浪费时间-却不会将响应发送给客户端?基本上,我想迫使邪恶的客户端进入超时状态,以至于减少其他烦恼我服务器的能力。

代码如下:

public class Webhook : IHttpModule
{
    /// <summary>
    /// You will need to configure this module in the Web.config file of your
    /// web and register it with IIS before being able to use it. For more information
    /// see the following link: http://go.microsoft.com/?linkid=8101007
    /// </summary>

    private bool m_sslRequired = false;

    #region IHttpModule Members
    <snip...>
    #endregion

    private void OnBeginRequest(object sender, EventArgs e)
    {
        WriteTrace("Begin OnBeginRequest");
        HttpContext ctx = HttpContext.Current;

        try
        {
            string processor = ctx.Request.Params["p"];
            if (processor != null && processor != "")
            {
                PluginProcessor(processor, ctx);
            }
        }
        catch (Exception ex)
        {
            ctx.Response.StatusCode = 500;
            ctx.Response.Write("ERROR");
        }

        ctx.ApplicationInstance.CompleteRequest();

        WriteTrace("End OnBeginRequest");
    }

    private void PluginProcessor(string processor, HttpContext ctx)
    {
        string pluginSpec = AppConfig.GetAppSetting(processor.Trim().ToLower());

        if (pluginSpec != "")
        {
            IWebhookProcessor proc = CreateProcessor(pluginSpec, ctx);
            proc.Process(ctx);
        }
    }

    private IWebhookProcessor CreateProcessor(string Processor, HttpContext ctx)
    {
        string assembly;
        string typeName;

        typeName = Processor.Substring(0, Processor.IndexOf(",")).Trim();
        assembly = Path.Combine(ctx.Request.PhysicalApplicationPath, "bin", Processor.Substring(Processor.IndexOf(",") + 1).Trim());

        var obj = Activator.CreateInstanceFrom(assembly, typeName);

        return (Interfaces.IWebhookProcessor)obj.Unwrap();
    }
}

因此,如果请求未映射到事务处理程序,则我想“挂起”客户端,但不希望这种方式占用服务器资源。

感谢您的建议!

1 个答案:

答案 0 :(得分:0)

我认为您可以做的最好的事情是使用HttpRequest.Abort(),它不会使客户端挂起,但是会立即切断TCP连接。甚至文档都说它适用于这种情况:

  

您可以使用此方法来响应恶意HTTP客户端的攻击。<​​/ p>

您将像这样使用它:

ctx.Request.Abort();

在浏览器中,您会看到“连接重置”错误。

另一种选择是发回意外的HTTP状态(例如400)或我个人的收藏夹418

更新:如果您真的想让客户端等待,则可以实现自己的HttpModule,以便可以进行异步{{1} }事件,然后使用BeginRequest

Task.Delay()类看起来像这样:

HttpModule

然后将模块添加到您的web.config中(将名称空间替换为应用程序的名称空间):

public class AsyncHttpModule : IHttpModule {
    public void Dispose() { }

    public void Init(HttpApplication app) {
        var wrapper = new EventHandlerTaskAsyncHelper(DoAsyncWork);
        app.AddOnBeginRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler);
    }

    private async Task DoAsyncWork(object sender, EventArgs e) {
        var app = (HttpApplication) sender;
        var ctx = app.Context;

        if (shouldDie) { //whatever your criteria is
            await Task.Delay(60000); //wait for one minute
            ctx.Request.Abort(); //kill the connection without replying
        }
    }
}

由于这是异步的,因此它在等待时不会占用线程。传入的其他请求将使用同一线程(我对此进行了测试)。

但是,由于请求仍在进行中,因此它仍将请求上下文保留在内存中。因此,如果他们用1000多个请求打了你,那么所有1000多个请求都会在内存中保留60秒钟。而如果您只是立即使用<system.webServer> <modules> <add name="AsyncHttpModule" type="MyNamespace.AsyncHttpModule" /> </modules> </system.webServer> ,则会立即将其从内存中删除。