原理很简单,就一句话:检查HTTP请求报头中的Referer字段是否为服务器网站的主机头,如果不是则决绝该请求。
完整的代码如下:
//filter.cpp
#include <windows.h>
// 包含了ISAPI过滤器所需的定义和原型
#include <httpfilt.h>
#include <stdio.h>
// 过滤器描述信息
#define FILTER_DESCRIPTION “Isapi Filter v1.0”
//SF_NOTIFY_READ_RAW_DATA通知处理
/*DWORD HandleEvent_ReadRawData(HTTP_FILTER_CONTEXT *pfc,
HTTP_FILTER_RAW_DATA *pReadData);*/
//SF_NOTIFY_URL_MAP通知处理
DWORD HandleEvent_OnUrlMap(HTTP_FILTER_CONTEXT *pfc,
HTTP_FILTER_URL_MAP *pUrlData);
// 获取文件的后缀名并转换为小写
char * GetFileExtensionLCase(char * filepath,char * extension,DWORD *dwSize);
// DLL入口
BOOL WINAPI DllMain(HINSTANCE hinstDll,DWORD dvReason,LPVOID lpv)
{
OutputDebugString(“DllMain\n”);
return TRUE;
}
//GetFilterVersion
BOOL WINAPI GetFilterVersion(HTTP_FILTER_VERSION *pVersion)
{
//设置过滤器版本号
pVersion->dwFilterVersion=HTTP_FILTER_REVISION;
//设置过滤器描述信息
strncpy(pVersion->lpszFilterDesc,FILTER_DESCRIPTION,SF_MAX_FILTER_DESC_LEN);
// 注册感兴趣的通知,设置过滤器的优先级
pVersion->dwFlags=(SF_NOTIFY_ORDER_HIGH|
SF_NOTIFY_SECURE_PORT| //Server在安全端口上收到一个客户连接
SF_NOTIFY_NONSECURE_PORT| //Server在非安全端口上收到一个客户连接
//SF_NOTIFY_READ_RAW_DATA | //Server从Client读取了数据
SF_NOTIFY_URL_MAP); //Server准备简化逻辑URL映射为实际路径
return TRUE;
}
// HttpFilterProc
DWORD WINAPI HttpFilterProc(HTTP_FILTER_CONTEXT *pfc,
DWORD dwNotificationType,VOID *pvData)
{
DWORD dwRet=SF_STATUS_REQ_NEXT_NOTIFICATION;
switch(dwNotificationType)
{
/*case SF_NOTIFY_READ_RAW_DATA:
dwRet=HandleEvent_ReadRawData(pfc,
(HTTP_FILTER_RAW_DATA *)pvData);
break;*/
case SF_NOTIFY_URL_MAP:
dwRet=HandleEvent_OnUrlMap(pfc,
(HTTP_FILTER_URL_MAP *)pvData);
break;
}
return dwRet;
}
/*
//SF_NOTIFY_READ_RAW_DATA通知处理
DWORD HandleEvent_ReadRawData(HTTP_FILTER_CONTEXT *pfc,
HTTP_FILTER_RAW_DATA *pReadData)
{
DWORD dwRet=SF_STATUS_REQ_NEXT_NOTIFICATION;
return dwRet;
}
*/
//SF_NOTIFY_URL_MAP通知处理
DWORD HandleEvent_OnUrlMap(HTTP_FILTER_CONTEXT *pfc,
HTTP_FILTER_URL_MAP *pUrlData)
{
DWORD dwRet=SF_STATUS_REQ_NEXT_NOTIFICATION;
char fileext[10]={0}; //文件后缀名
DWORD dwSize=0;
// 获取文件的后缀名,并转换为小写
dwSize=10;
GetFileExtensionLCase(pUrlData->pszPhysicalPath,fileext, &dwSize);
if(dwSize)
{
//如果文件后缀名为gif,jpg,png中的一种
if(!strcmp(fileext,”gif”) || !strcmp(fileext,”jpg”) || !strcmp(fileext,”png”) )
{
//检查HTTP报头中Referer
char Referer[256]={0};
char Host[256]={0};
dwSize=256;
pfc->GetServerVariable(pfc,”HTTP_REFERER”,Referer,&dwSize);
OutputDebugString(Referer);
dwSize=256;
if(pfc->GetServerVariable(pfc,”HTTP_HOST”,Host,&dwSize));
OutputDebugString(Host);
if(!strstr(Referer,Host)) //如果Referer中不含有Host
{
//我们决绝这次请求,或者修改pUrlData->pszPhysicalPath的值
pfc->ServerSupportFunction(pfc,SF_REQ_SEND_RESPONSE_HEADER,
“403 Forbidden \r\n”,0,(DWORD)NULL);
return SF_STATUS_REQ_FINISHED;
}
}
}
return dwRet;
}
// 获取文件的后缀名并转换为小写
char * GetFileExtensionLCase(char * filepath,char * extension,DWORD *dwSize)
{
unsigned int i=0,j=0;
for(;i<strlen(filepath);i++)
{
if(filepath[i]!=’\\’ && filepath[i]!=’.’)
{
if(j>*dwSize-2)
{
memset(extension,0,*dwSize);
j=0;
}
extension[j++]=filepath[i];
}
else
{
memset(extension,0,*dwSize);
j=0;
}
}
*dwSize=j+1;
return _strlwr(extension);
}
//Moudle.def
EXPORTS
GetFilterVersion
HttpFilterProc
DllMain