🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.web
1 messages
1 total messages Started by Borland Lover Wed, 17 May 2006 20:17
HELP: defend against brute force on an ISAPI module?
#605
Author: 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.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads