🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.internet.web
Article #605

HELP: defend against brute force on an ISAPI module?

#605
From: Borland Lover
Date: Wed, 17 May 2006 20:17
163 lines
5752 bytes
Hi,  BCB6.  Questions are short but the post is long due to code - please 
read on.

I have an ISAPI application that exposes some SOAP web-services.  I want to 
defnd against brute-force programatic attacks on the server such that: If a 
large number of requests come in in less than a predefined period of time 
from a single IP - to simply drop the requests and stop responding to that 
IP (at least temporarily).  While continuing to service requests from 
others.  I think I have a fair underastanding of the threading issues in 
ISAPI apps and am prepared to handle them - but this problem is a bit of a 
beast.

So far I have the folowing concept:


1) Declare a *global* threadlist:

TThreadList * pIncomingRequests = NULL;


2)  When a web-module gets constructed ensure the global thread list is 
created:

__fastcall TMyWM::TMyWM(TComponent* Owner)
 : TWebModule(Owner)
{
    if (! pIncomingRequests)
    {
        pIncomingRequests = new TThreadList();
    }
}


3) Define a structure to hold info on requesters to be added to the global 
thread list:

class TIncomingRequester : public TObject
{
public:
    AnsiString FIP; // IP address
    DWORD FNumRequests; // number of times request recieved from this IP
    TDateTime FFirstRequestTime;
    TDateTime FLastRequestTime;
    __fastcall TIncomingRequester(const AnsiString AnIP, const TDateTime 
ADateTime);
};


4) And some constants to define maximum requests per period:

const int MAXREQUESTSPERQUANTA = 100;
const int REQUESTQUANTA = 5; // 5minutes


5) Before a request gets dispatched - decide whether or not to bother 
responding by checking the requester against the list:

void __fastcall TMyWM::WebModuleBeforeDispatch(TObject *Sender,
      TWebRequest *Request, TWebResponse *Response, bool &Handled)
{
    TList * lockedList = pIncomingRequests->LockList();

    try
    {
        RemoveOldRequests(lockedList);
        TIncomingRequester* pIR = NULL;
        for (int i = 0; i < lockedList->Count; ++i)
        {
            pIR = (TIncomingRequester*)lockedList->Items[i];

            if (pIR->FIP == Request->RemoteAddr)
            {
                break;
            }
        }

        if (pIR)
        {
            pIR->FNumRequests++;
            pIR->FLastRequestTime = Now();
        }
        else
        {
            pIR = new TIncomingRequester(Request->RemoteAddr, Now());
            lockedList->Add(pIR);
        }
        Handled = IgnoreRequester(pIR);
    }
    __finally
    {
        pIncomingRequests->UnlockList();
    }
}

//---------------------------------------------------------------------------
bool __fastcall TMyWM::IgnoreRequester(TIncomingRequester * pIR)
{
    if (!pIR)
        return true;
    else
        return (   (pIR->FNumRequests > MAXREQUESTSPERQUANTA)
                && (MinutesBetween(pIR->FLastRequestTime, 
pIR->FFirstRequestTime) < REQUESTQUANTA));
}

//---------------------------------------------------------------------------
void __fastcall TMyWM::RemoveOldRequests(TList * ALockedList)
{
    if (ALockedList)
    {
        TIncomingRequester* pIR = NULL;
        const TDateTime utcNow = Now();
        for (int i = ALockedList->Count - 1; i >= 0 ; --i)
        {
            pIR = (TIncomingRequester*)ALockedList->Items[i];
            if (MinutesBetween(pIR->FFirstRequestTime, utcNow) > 
REQUESTQUANTA)
            {
                // remove it
                ALockedList->Remove(pIR);
            }
        }
        ALockedList->Pack();
    }
}



So far so good....  I think... First question is - do you see any problem 
with what I have so far?  How would you do it better?

One main thing I am concerned about is memory.  I need to (at some point) 
destroy the thread list.  In the destructor I have:


__fastcall TMyWM::~TMyWM()
{
    if (pIncomingRequests)  // and i am the last web-module ! ???
    {
        TList * lockedList = pIncomingRequests->LockList();
        for (int i = 0 ; i < lockedList->Count; ++i)
        {
            delete (TIncomingRequester*)lockedList->Items[i];
        }

        delete pIncomingRequests;
        pIncomingRequests = NULL;
    }
}


However - as you can see - I don't know how to determine if indeed *this* 
web-module is the *last* web-module to be destroyed because the dll is being 
unloaded.  This is important because if a web-module is destroyed in an 
ISAPI it does not necessarily mean that there are no other web-modules 
(either inactive or active) in the thread pool - in fact there could be many 
that are still working with the list.  If the rest of my methodology is OK, 
how do I solve this problem?



Thank You.
M.
Technical Details
Message-ID: <446b84e8$1@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news2.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!newsfeed.freenet.de!news.ispa.de!news.albasani.net!reader.uucp.at!newsfeed.uucp.at!news.uucp.at!newsgroups.borland.com!not-for-mail

Show Full Headers
Complete Article Headers
X-Google-Thread: feeec,9b95558a7696a165,start
X-Google-Attributes: gidfeeec,public
X-Google-Language: ENGLISH,ASCII-7-bit
From: "Borland Lover" <kdhf@kbdf.com>
Newsgroups: borland.public.cppbuilder.internet.web
Subject: HELP: defend against brute force on an ISAPI module?
Date: Wed, 17 May 2006 13:17:41 -0700
Lines: 172
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2900.2869
X-RFC2646: Format=Flowed; Original
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869
NNTP-Posting-Host: 207.61.87.125
Message-ID: <446b84e8$1@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1147897064 207.61.87.125 (17 May 2006 13:17:44 -0700)
Path: arc1-ca.pugleaf.net!g2news2.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!newsfeed.freenet.de!news.ispa.de!news.albasani.net!reader.uucp.at!newsfeed.uucp.at!news.uucp.at!newsgroups.borland.com!not-for-mail