222 lines
6.9 KiB
C++
222 lines
6.9 KiB
C++
#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;
|
||
} |