Article View: borland.public.cppbuilder.internet.web
Article #605HELP: defend against brute force on an ISAPI module?
From: Borland Lover
Date: Wed, 17 May 2006 20:17
Date: Wed, 17 May 2006 20:17
163 lines
5752 bytes
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-mailShow 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