Files
FcltISAPI/fcltisapi.cpp
Jos Groot Lipman 0c15e026d1 UWVA#31069 Betere detectie IIS 7.5
svn path=/FcltISAPI/trunk/; revision=23459
2014-11-26 10:56:13 +00:00

222 lines
6.9 KiB
C++
Raw Blame History

#include "stdafx.h"
#include <httpfilt.h>
#include "tchar.h"
#include "time.h"
#define FCLT_ISAPI_VERSION "1.01"
// http://believeinmiraclesx.wordpress.com/2013/11/19/isapi-filter-set-httponly-for-mulitple-cookies/
// http://stackoverflow.com/questions/17649213/how-to-set-multiple-cookies-in-isapi-filter
// TODO: Bij API's blijft er van de dubbele userid nog eentje over volgens Fiddler?
#define bufferSize 4096 // increase size if using many cookies
#define FCLT_USERID "FCLT_USERID:"
class CMyContext
{
public:
CMyContext(HTTP_FILTER_CONTEXT* pFC)
: startTime( clock() )
{
userid[0] = 0;
CHAR szCookie[2048];
DWORD cbCookie = sizeof(szCookie) / sizeof(szCookie[0]);
pFC->GetServerVariable(pFC, "SERVER_SOFTWARE", szCookie, &cbCookie);
iis_version = 7;
if (strstr(szCookie, "IIS/6.0")) // 2008R2 is 7.5, 2012 is 8.0?
iis_version = 6;
}
clock_t GetStartTime()
{
return startTime;
}
void get_userid(HTTP_FILTER_CONTEXT* pFC, HTTP_FILTER_SEND_RESPONSE* pResponseInfo)
{
CHAR uid[32];
uid[0] = '\0';
DWORD dwuid = sizeof(uid) / sizeof(uid[0]);
pResponseInfo->GetHeader(pFC,FCLT_USERID, &uid, &dwuid);
// Bij API's staat er wel eens eentje dubbel in de header
char *next_token = NULL;
char *token = strtok_s (uid, ",", &next_token);
if (token != NULL)
{
strcpy_s(userid, token);
}
}
private:
clock_t startTime;
public:
int iis_version;
CHAR userid[32];
};
DWORD OnPreprocHeaders (HTTP_FILTER_CONTEXT* pFC,
HTTP_FILTER_PREPROC_HEADERS* pHeaderInfo)
{
//pHeaderInfo->SetHeader(pFC,"FCLT_VERSION:", FCLT_ISAPI_VERSION); // komt niet in Request.Servervariables?
pHeaderInfo->SetHeader(pFC,"FCLT-VERSION:", FCLT_ISAPI_VERSION); // Request.Servervariables("HTTP_FCLT_VERSION");
return 0;
}
// Onderschept alle uitgaande cookies en plakt er httponly achteraan
DWORD OnSendResponse (HTTP_FILTER_CONTEXT* pFC,
HTTP_FILTER_SEND_RESPONSE* pResponseInfo)
{
CMyContext* pContext = (CMyContext *)pFC->pFilterContext;
if (!pContext)
return SF_STATUS_REQ_NEXT_NOTIFICATION;
// Hard coded cookie length (2k bytes)
CHAR szCookie[2048];
DWORD cbCookie = sizeof(szCookie) / sizeof(szCookie[0]);
// Bij IIS 6 moeten we de cookies stuk voor stuk vervangen met SetHeader
// Bij IIS 7 moeten we de cookies wissen via eenmalig SetHeader en toevoegen met AddHeader
CHAR *szHeader = "Set-Cookie:";
CHAR *szHttpOnly = "; HttpOnly";
if (pResponseInfo->GetHeader(pFC,szHeader,szCookie,&cbCookie))
{
// http://msdn.microsoft.com/en-us/library/ms972826 ondersteunt maar <20><>n cookie
// Met meerdere cookies
// ASPFIXATION=UWVAnJAYKAozuKPNBuKpCIINamAJZqMwRhut; path=/Facilitor5iWork/,userid=33083; path=/Facilitor5iWork/
// maar pas op met:
// fcltidxxxx; expires=Sun, 16-Dec-2012 21:54:34 GMT; path=/Facilitor5iWork/
// Daar zit wel een komma in maar toch is het maar <20><>n cookie
if (pContext->iis_version == 7)
pResponseInfo->SetHeader(pFC,szHeader,""); // alle standaard cookies wissen
CHAR outCookie[2048];
DWORD cboutCookie = sizeof(outCookie) / sizeof(outCookie[0]);
char * token;
char *next_token = NULL;
// the last occurence of semicolon
char * semi;
token = strtok_s (szCookie,",", &next_token);
while (token != NULL)
{
strcpy_s(outCookie, token);
// Eindigt de cookie tot zoverre op 'expires=Sun'?
char *expires = strstr ( token, "expires=");
if (expires + strlen("expires=Sun") == token + strlen(token) )
{ // plak dan het volgende token er ook nog achter
token = strtok_s (NULL, ",", &next_token);
if (token != NULL)
strcat_s (outCookie, cboutCookie, token);
}
semi = strrchr(token, ';');
//if the last character is ;
if (semi - token == strlen(token) - 1){
strcat_s (outCookie, cboutCookie, " HttpOnly");
}
else{
strcat_s (outCookie, cboutCookie, "; HttpOnly");
}
if (pContext->iis_version == 6)
pResponseInfo->SetHeader(pFC, szHeader, outCookie); // 1-voor-1 vervangen
else // ie7
pResponseInfo->AddHeader(pFC, szHeader, outCookie); // 1-voor-1 terug
memset(outCookie, 0, cboutCookie);
token = strtok_s (NULL, ",", &next_token);
}
}
pContext->get_userid(pFC, pResponseInfo);
pResponseInfo->SetHeader(pFC, FCLT_USERID, '\0'); // Niet meer nodig nu
// Altijd Server: Microsoft-IIS/6.0 verwijderen
pResponseInfo->SetHeader(pFC, "Server:", "FACILITOR");
// Altijd X-Powered-By: ASP.NET verwijderen
// Kan ook gewoon in de interface van IIS Admin maar we hebben
// deze DLL nu toch
pResponseInfo->SetHeader(pFC, "X-Powered-By:", '\0');
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
// Onderschept binnenkomende cookies en gebruikt eerder opgeslagen userid voor de logging
DWORD OnLog(HTTP_FILTER_CONTEXT* pFC, PHTTP_FILTER_LOG pLog)
{
// OnSendResponse heeft de userid voor ons bewaard
CMyContext* pContext = (CMyContext *)pFC->pFilterContext;
// SF_NOTIFY_PREPROC_HEADERS schijnt niet aangeroepen te worden tijdens SAML
// en dan was pFC->pFilterContext nog leeg
if (!pContext)
return SF_STATUS_REQ_NEXT_NOTIFICATION;
if (pContext->userid[0])
{
pLog->pszClientUserName = pContext->userid;
}
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
BOOL WINAPI GetFilterVersion(
PHTTP_FILTER_VERSION pVer
)
{
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strncpy_s( pVer->lpszFilterDesc, "FCLTISAPI_" FCLT_ISAPI_VERSION, SF_MAX_FILTER_DESC_LEN );
/* Notify me when headers have been processed */
pVer->dwFlags = SF_NOTIFY_ORDER_DEFAULT |
SF_NOTIFY_PREPROC_HEADERS | // Om version toe te voegen
SF_NOTIFY_SEND_RESPONSE | // Om cookies te manipuleren
SF_NOTIFY_LOG | // Om userid te loggen
SF_NOTIFY_END_OF_REQUEST; // Om geheugen vrij te geven
return TRUE;
};
// Portion of HttpOnly
DWORD WINAPI HttpFilterProc(
PHTTP_FILTER_CONTEXT pFC,
DWORD dwNotificationType,
LPVOID pvData) {
DWORD dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
switch (dwNotificationType)
{
case SF_NOTIFY_PREPROC_HEADERS:
{
// AllocMem wordt vanzelf opgeruimd aan einde sessie
CMyContext pContext(pFC);
pFC->pFilterContext = pFC->AllocMem(pFC, sizeof(CMyContext), 0);
memcpy(pFC->pFilterContext, &pContext, sizeof(CMyContext));
dwRet = OnPreprocHeaders( pFC, (PHTTP_FILTER_PREPROC_HEADERS) pvData );
break;
}
case SF_NOTIFY_SEND_RESPONSE:
dwRet = OnSendResponse( pFC, (PHTTP_FILTER_SEND_RESPONSE) pvData );
break;
case SF_NOTIFY_LOG:
dwRet = OnLog( pFC, (PHTTP_FILTER_LOG) pvData );
break;
case SF_NOTIFY_END_OF_REQUEST:
// time = clock() - pContext->GetStartTime();
//
// pContext wordt vanzelf opgeruimd
//
break;
default:
dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
break;
}
return dwRet;
}