[原创-开源]ISAPI Filter实现网站资源防盗链

作者在 2008-12-25 13:14:34 发布以下内容
//ISAPI Filter实现网站资源防盗链
//by redice 2008.12.25 redice@163.com

原理很简单,就一句话:检查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

或给我发Email索取源码。。。


本博客于即日起(2009.2.26)停止更新,

新博客地址:http://www.redicecn.cn ,

本博客的大部分文章已经转移到新博客中...


默认分类 | 阅读 5696 次
文章评论,共0条
游客请输入验证码
浏览585133次