现在一些单位为了避免资料泄露,都实行了隔离外网的措施,但是这样的单位往往分支机构比较多,很难保证所有的下级分支机构不会自己接入光纤、开通ADSL,实际上造成了内网、外网两网隔离工作的失败。这里提出一个在两网隔离情况下非法连接外网的检测方法,这个也是一个08年工作内容之一的总结。
首先,我们需要向所有用户工作用机部署一个常态运行的软件,可以是桌面管理程序,也可以是其他均需要有的程序,我们在这个程序的基础上做一定的开发工作。
业务流程图如下:
首先在某个应用MIS中完成对部门、人员、IP段是否可以连通互联网的权限进行设置,有连通互联网权限的终端可以不做外网连接检测,相当于设置外网连接检测的免检名单。
根据设置的连接外网检测权限和系统设置的本地Web应用URL前缀、外连检测URL、外联检测程序尝试使用路由检测、IE历史记录检测、maxthon历史记录检测、Firefox历史记录检测、代理上网检测、其他常用网络软件检测等手段检测桌面终端和外网连通情况。这种方式避免传统靠检测附加硬件设备(判断是否存在Modem等)判定的方式的局限性,更为通用和有效。
路由检测法:尝试路由到指定IP,并获取返回的路由结果。判定给定网关前缀是否在路由链中,如果在则说明通过路由检测,否则说明存在连接外网行为。
IE历史记录检测:通过编程实现获取IE的浏览页面历史记录,并剔除URL前缀符合管理员设置的本地web应用URL(自动剔除file://开头的本地文件URL),形成桌面终端用户访问网页历史记录,判定用户是否访问外网。
Firefox历史记录检测:探测firefox路径,通过编程实现获取Firefox的浏览页面历史记录,并剔除URL前缀符合管理员设置的本地web应用URL(自动剔除file://开头的本地文件URL),形成桌面终端用户访问网页历史记录,判定用户是否访问外网。Firefox 的url历史记录,可参考firefox源代码或者处理local data 目录下\Mozilla\Firefox\Profiles\******.default\Cache下的文件。另外,在firefox下访问about:cache可以看到url访问历史记录。
直连及代理上网检测:在系统设定的外连检测url中挑选3~5条作为检测项。直接使用socket连接这些检测项的URL,如果能够正常返回数据,在检测返回的数据中是否包含检测项中指定的检测字符串,如果包含则说明该桌面终端连接到外网,如果连接URL是socket出现错误,则判定不能连接外网。读取注册表(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\)中的ProxyEnable项,如果值为0或读取失败,则判定不能连接外网,如果值为非0值,读取ProxyServer的值,依次使用该值提供的代理设置,尝试使用代理连接这些检测项的URL,如果能够正常返回数据,在检测返回的数据中是否包含检测项中指定的检测字符串,如果包含则说明该桌面终端连接到外网,如果连接URL是socket出现错误,则判定不能连接外网。
其他常用网络软件检测:根据系统设定的外连检测程序,在系统的进程列表中检测是否存在管理员指定的进程,如果存在则判定连接外网。
其中每个检测所需要的参数均需要通过管理控制台来设置,在检测到有外网连接的时候,可以通过网管工具或者其他手段自动断开内网或者告警。
获取IE访问历史记录参考代码如下:
//Powered by fOx,转载请保留作者信息 : Email Destiny-fOx@hotmail.com void GetUrlHistoryMethod2() { HANDLE hFind = NULL; DWORD dwSize = NULL; hFind = ::FindFirstUrlCacheEntryA("visited:",NULL,&dwSize); HANDLE hHeap = ::HeapCreate(NULL,0x100,0x10000000); LPINTERNET_CACHE_ENTRY_INFOA pInfo = (LPINTERNET_CACHE_ENTRY_INFOA)::HeapAlloc(hHeap,LPTR,dwSize); hFind = ::FindFirstUrlCacheEntryA("visited:",pInfo,&dwSize); if(hFind) { int n = 0; while(pInfo != NULL) { /* typedef struct _INTERNET_CACHE_ENTRY_INFOA { DWORD dwStructSize; // version of cache system.0 LPSTR lpszSourceUrlName; // embedded pointer to the URL name string.4 LPSTR lpszLocalFileName; // embedded pointer to the local file name.8 DWORD CacheEntryType; // cache type bit mask.C DWORD dwUseCount; // current users count of the cache entry.10 DWORD dwHitRate; // num of times the cache entry was retrieved. DWORD dwSizeLow; // low DWORD of the file size. DWORD dwSizeHigh; // high DWORD of the file size. FILETIME LastModifiedTime; // last modified time of the file in GMT format. FILETIME ExpireTime; // expire time of the file in GMT format FILETIME LastAccessTime; // last accessed time in GMT format FILETIME LastSyncTime; // last time the URL was synchronized // with the source LPSTR lpHeaderInfo; // embedded pointer to the header info. DWORD dwHeaderInfoSize; // size of the above header. LPSTR lpszFileExtension; // File extension used to retrive the urldata as a file. union { // Exemption delta from last access time. DWORD dwReserved; DWORD dwExemptDelta; }; // Exemption delta from last access } INTERNET_CACHE_ENTRY_INFOA, * LPINTERNET_CACHE_ENTRY_INFOA; */ LPBYTE p = (LPBYTE)(pInfo->lpHeaderInfo); p += *(PWORD)p; if(p != NULL) if(p[2] != 0x10) p = NULL; else { if(p[3] == 0x1F) p += 4; else p = NULL; } printf("[%d] SourceUrlName : %s ,LocalFileName : %s Title : %S \r\n" ,n,pInfo->lpszSourceUrlName,pInfo->lpszLocalFileName,p); n++; pInfo = NULL; dwSize = 1000; pInfo = (LPINTERNET_CACHE_ENTRY_INFOA)::HeapAlloc(hHeap,LPTR,dwSize); if(pInfo == NULL) { DWORD dwError = ::GetLastError(); printf("HeapAlloc Error : %d\r\n",dwError); } BOOL bSus = ::FindNextUrlCacheEntryA(hFind,pInfo,&dwSize); if(bSus == FALSE) { pInfo = NULL; DWORD dwError = ::GetLastError(); printf("Error : %d\r\n",dwError); } } ::FindCloseUrlCache(hFind); ::HeapDestroy(hHeap); } }

Dominic