许多网站在接受HTTP输入的时候常用到一项认证码技术来防止DOS攻击。简单地说就是在显示提交数据页面之前或者同时,服务器会向客户端发送一个小图片,该图片通常由一些随机的数字或字母(很少情况下会有其他字符)组合而成,并要求在HTTP的提交表单(FORM)中正确输入该数字,无效的输入会使数据提交失败。这样的机制可以有效阻止或降低一些登陆/张贴/投票的自动机对网站产生的负面作用。
作者:doublelee
日期:2005-5-5
概述:
许多网站在接受HTTP输入的时候常用到一项认证码技术来防止DOS攻击。简单地说就是在显示提交数据页面之前或者同时,服务器会向客户端发送一个小图片,该图片通常由一些随机的数字或字母(很少情况下会有其他字符)组合而成,并要求在HTTP的提交表单(FORM)中正确输入该数字,无效的输入会使数据提交失败。这样的机制可以有效阻止或降低一些登陆/张贴/投票的自动机对网站产生的负面作用。
早期的认证图片是一个图片库的形式存放在服务器端,每次随机选取一幅图片发送到客户端。对这样的认证机制有一个相当简单的攻击方法就是,攻击者可以用自动机经过一定时间穷举,下载所有的图片并经过人工辨认,存入攻击者的数据库,攻击时,根据得到的图片或者甚至是其校验和,在数据库中查询其对应的认证码即可。对于一个4位数字的情况,攻击者只要存储一万张图片即可,这其实是一个很小的工作量。
针对上述攻击方法,现在有很多jsp,php,cgi的脚本可以动态生成这样的认证图片,即先随机产生认证码,再根据认证码动态生成图片。这样同样的认证数字生成的图片完全不同,使得储存图片库的攻击方式失效。但也许由于技术原因限制,动态生成的图片在字体变形方面通常做的很差,大多数甚至完全没有变形机制,这样的情况下,编写程序识别这样的图片也就成为了可能。
本文就以国内某网站为例,谈一下编写这样的图片自动识别工具的思路。
正文:
首先图片格式不外乎bmp,jpg,gif,可以通过开源程序全部转换为统一格式,故不予考虑。这里只考虑bmp格式作为目标,因为这是最简单和易于处理的格式。
现在我们来分析图片的构成,发出了50个请求之后,我们得到了这样50个图片,其中包含一对同样数字图片 7208
经过分析,图片内容为4位数字,不含字母或其他符号。图片格式为bmp,所有图片具有统一的大小,宽,高。经过查询bmp文件格式文档,发现其调色板也完全相同,以2字节代表一个象素。另外还发现图片所有的数字所处的相对位置固定,大小固定,字体固定,变化的只是颜色和背景中一些随机的黑色斑点。而且颜色上,也许是考虑色盲用户的存在,并没有过于鲜艳的颜色,也就是说基本上数字轮廓内的颜色以深色高灰度为主,变化并不大。背景中的斑点也是一样。数目约40 个象素左右(图片共17*60=1020象素)
进一步分析,确定各数字所处的位置,所占的象素。由于bmp文件格式很简单,这个工作细心一点很快就可以完成。得到数据如下:
//图片高17,宽60,以下x,y是第一象限坐标
//每个数字高13,宽10,字间间隙为3
//起始坐标依次在(x,y) = (7,1), (20,1), (33,1), (46,1)
//每个象素占用2个字节
根据以上这些数据,可以在程序中轻松定位每一个数字并提取出代表该位置数字的所有象素的数据信息,这些信息可以存在一个2*13*10=260字节的一个数组里。
下面的问题是如何准确判断这260个字节数据代表的数字,这涉及到一个模糊匹配的问题。好在在本例中,匹配目标只有十个,干扰元素影响也不是很大。经过几次摸索,我认为产生10个标准的匹配目标即可,这个匹配目标我称之为数字模板(module),共10个,分别代表0~9数字的典型灰度分布,每个数字模板也占用260个字节。这样以后将每次得到的260字节数据与之比较,差异最小的即认为最匹配即可。
现在产生两个问题,一,模板文件哪里来?二,比较函数用什么公式?
对于第一个问题,我可不想260个字节一个字节一个字节地手工查找和填写,2600次,很累的也!那么想办法写程序统计。最开始我是统计所有的相同数字,取平均值,例如每看到一个0,假设前面已经统计过k个0,模板中的对应字节的值是前k个数字0统计的平均值,那么看到第k+1个0的图片p0(k+1)之后,修正模板为
m0(k+1)=(m0(k)*k+p0)/(k+1)
但是随即发现问题,对于不同的颜色,p0(k)的差异很大,平均值不能体现问题。更为严重的是,作为整数,这样的包含除法的平均值计算公式并不好用,误差十分的大,经过一些轮次的计算后,模板数据变的一塌糊涂,新数据也很难以起作用了。
再次对数据进行仔细地观察,发现深色象素处,高位字节的值一般小于0xc0,但具体的值由颜色决定,差异很大,但浅色象素的高位字节大于0xc0,肉眼观察图片实际上得到的印象只由象素的灰度决定,具体颜色并不要紧。因此我作了一个修正,就是取0xc0为阈值,大于此数的取1,小于此数的取0,用加法修正到模板对应的字节上,同时对每个模板增加一个记数器module_weight,记录模板是统计过多少个源图片而得来的。并且如果统计到255个就不再统计。保证各模板的数据基本权重相等。后来证明这个做法很有效。
第二个问题,我开始想使用各字节差的绝对值之和,即
Sigma(abs(x(i)-m(i))) i=0,1,...259
来表示,这里x(i)表示要判断的图片的第i个字节,m(i)表示模板中第i个字节的值。
后来发现这个数字的值受颜色影响比较大,那么我们需要增大每一对象素差异对整体比较函数的影响。为了达到这一目的,除了修改模板文件以外,还必须对判断公式进行调整。如果学过概率论的一些基本知识就知道,统计其二阶中心矩,也就是方差将是一个不错的选择。
现在公式调整为
Sigma ((x-m)^2)
好了,基本问题都解决了。调整程序试试吧。注意到每个象素是2字节,即一个short型数据,两个short型数据的差的平方应该用int型变量记录,这样 260个int变量加起来会溢出的。为了程序简洁,不处理大整数,我将每个象素的2字节分开处理,其平方用short即可记录,260个unsinged short变量的和,哈哈,unsigned int怎么也不会溢出了吧。
搞定!
程序:
以下是c的源代码,还不到200行,处理bmp文件格式,包含了生成模板的功能,即study函数
//-------------------------------------------------------------------------------------------
// File Name: myocr.c
// special crafted for xxxx.com's image.
// by doublelee@etang.com
#include
#include
#define MOD_FILE "digit.mod"
unsigned char map[4][260]; //每图4个数字,每个数字用260个byte表示
unsigned char module[10][260]; //模板10个,代表0~9,也用260 bytes.
unsigned char buf[0x083a]; //文件大小,固定
unsigned char module_weight[10];//训练次数,增到255就不再增
unsigned int diff, tmpdiff ; //diff表示该数字与模板的相似度,现在用 sigma ((x-m)^2) 判断。
//tmpdiff表示到现在为止最相似的值。越小越相似
char value[4]={0}; //储存结果,值必定在0~9之间
void readmap() //从buf的相应位置读入图片数据
{
int i; //第i个数字
int x,y; //坐标
for(i=0; i<4; i++)
for(x=0; x<20; x++)
for(y=0; y<13; y++)
{
map[i][x+y*20] = buf[ 0x42 + (7+13*i+60*(y+1))*2 + x ];
//图片高17,宽60,x,y是第一象限坐标
//每个数字高13,宽10,字间间隙为3
//起始坐标依次在(x,y) = (7,1), (20,1), (33,1), (46,1)
//每个象素要2个字节,因此有以上公式,0x42是BMP头长
//其实还可以改进,每个象素只判断高位字节(和灰度关系比较大?),准确性应该还可以提高
//现在的测试结果已经比较令人满意
}
return;
}
void outputvalue() //输出结果
{
int i;
for(i=0;i<4;i++)
fprintf(stdout, "%d", value[i]);
return;
}
int read_mod()
{
FILE* fp;
fp = fopen(MOD_FILE, "r+b");
if(!fp)
{
memset(module, 0, 10*260);
memset(module_weight, 0, 10);
return 0;
}
fread(module, 10, 260, fp);
fread(module_weight, 10, 1, fp);
fclose(fp);
return 1;
}
int write_mod()
{
FILE* fp;
fp = fopen(MOD_FILE, "w+b");
if(!fp)
return 0;
fwrite(module, 10, 260, fp);
fwrite(module_weight, 10, 1, fp);
fclose(fp);
return 1;
}
int checkbmp(FILE* fd)
{
int x;
if(!fd)
return 0;
fread(&x, 1, sizeof(int), fd);
if(x!=0x083a4d42) return 0;
fseek(fd, -1, SEEK_END);
x = ftell(fd);
if(x+1!=0x083a)
return 0;
//以上是基本检查,其实可以检查更多的BMP头结构字段
rewind(fd);
fread(buf, 1, 0x083a, fd);
readmap();
return 1;
}
void checkdigit() //判断函数
{
int i,j,k;
unsigned char x;
for (i=0;i<4;i++)
{
diff = 0;
tmpdiff = 0xffffffff;
for (j=0;j<10;j++)
{
diff = 0;
for (k=0;k<260;k++)
{
x = module[j][k]>map[i][k] ?
(module[j][k]-map[i][k]) :
(map[i][k]-module[j][k]);
diff += x*x;
}//计算 Sigma ((x-m)^2)
if(diff{
value[i] = j;
tmpdiff = diff;
}
}//遍历完10个模板
}//4个数字全部解决
}
int study() //训练函数
{
int i,j;
for(i=0;i<4;i++)
{
if(module_weight[value[i]] != 0xff)
{
for(j=0;j<260;j++)
{
module[value[i]][j] += (map[i][j]>0xc0? 1:0 );
}
module_weight[value[i]]++; //又训练完一次
}
}
return 0;
}
int main(int argc, char** argv)
{
FILE* fd;
int i,ret ;
read_mod();
if(argc == 1)
fd = stdin;
if(argc > 1)
{
fd = fopen(argv[1],"rb");
if(!fd)
{
fprintf(stderr, "open file %s failed ", argv[2]);
return 0;
}
}
if(argc > 2) //后跟训练数字
{
for(i=0;i<4;i++)
{
value[i]=argv[2][i]-0x30;
if(value[i]>9 || value[i]<0)
{
fprintf(stderr, "wrong number %s ", argv[2]);
return 0;
}
}
checkbmp(fd);
ret = study();
write_mod();
return ret;
}
if(checkbmp(fd))
{
checkdigit();
outputvalue();
}
if(fd) fclose(fd);
return 1;
}
//----------------------------------------------------------------------------------------------------------------
这个程序维护和依赖一个模板文件digit.mod,如果只有一个参数,则认为是bmp文件名,根据模板文件判断其所代表的数字,例如
myocr 2110.bmp
如果有两个参数,则认为进入学习模式,根据argv[1]代表的bmp文件和argv[2]代表的数字,对模板文件digit.mod进行修改。例如
myocr 2110.bmp 2110
我写了一个bat文件执行所有的训练,多次训练结束后,digit.mod文件中所有的module_weight都变为0xff,就可以了。
以上是针对某个特定网站的图片识别程序,对其中的参数稍加调整就可以对很多这样的图片实现程序辨认。
结论:
纵观整个认证码技术体系,现在基本可以分为静态图片库技术和动态生成技术。
静态图片库方式的确可以通过强烈的变形技术防止程序识别,但太少的图片数目容易被穷举,而生成这样的图片库需要人工参与,否则难以保证可识别程度。所以代价偏高。
动态图片技术由于程序复杂度原因,并兼顾到可识别性,往往不能做到很好的变形甚至没有变形,这样给程序实现攻击提供了可乘之机,对这样的动态图片的攻击可以总结为一句话,“用程序生成的东西是很容易被程序辨认出来的。”
事实上图片认证技术对防止WEB机器人确实起到了一定的作用,但是由于其实现的局限性,并不能完全依赖这种技术保证网站的安全性。
分享到:
相关推荐
至于提供的"ZT13085E封装库",这包含ZT13085E芯片的原理图符号库和PCB封装库。原理图符号库是电路设计软件中表示该芯片的图形符号,用于绘制电路原理图;PCB封装库则包含芯片在PCB板上的实际物理尺寸和引脚布局,...
斑马打印机ZT411和ZT421是工业级条码和标签打印机,广泛应用于制造业、物流、零售业等对打印质量和效率有高要求的领域。这两款打印机以其出色的性能、耐用性和易用性赢得了用户的信赖。这份中文手册详细地介绍了ZT...
《ZT213/ZT213LEEA:低功耗RS232多通道USB收发器/驱动器芯片详解》 ZT213/ZT213LEEA是一款专为低功耗应用设计的RS232多通道USB收发器和驱动器芯片,广泛应用于数据通信、工业控制、物联网设备等领域。本文将深入...
本驱动程序专为Zebra的ZT210、ZT220及ZT230系列打印机设计,提供了全面的功能支持,以实现高质量的条形码、二维码以及其他标签打印。 1. **驱动程序安装** - `zd51166465-certified.exe` 是Zebra ZT230系列打印机...
ZT7548的设计目标是实现混合触摸功能,具备自我和互电容感应技术,从而提供增强的防水、悬停、高电压感应、手套触摸和增强的触控笔检测能力。此外,该触控IC支持CDMS(SF)增强SF技术和高信噪比(SNR)。 ZT7548...
ZT410打印机IP地址设置网络打印机ZT410打印机IP地址设置网络打印机ZT410打印机IP地址设置网络打印机ZT410打印机IP地址设置网络打印机ZT410打印机IP地址设置网络打印机
斑马(Zebra)ZT410是一款先进的桌面级条码打印机,被广泛应用于物流、零售、医疗、制造业等多个行业。这款打印机以其高效、耐用和易于操作的特点深受用户喜爱。"斑马zt410中文库"指的是为ZT410打印机特别设计的中文...
"斑马打印机ZT210用户指南" 本用户指南旨在为Zebra ZT210/ZT220/ZT230打印机的用户提供操作和维护指南,该设备是一种工业级的条码打印机,具有高速打印、高速处理和高质量打印输出等特点。 版权信息 本手册的版权...
证通ZT598是一款专门用于金融、安防等领域,具备高安全性和可靠性的金属键盘设备。这款设备的开发资料包含在"证通ZT598金属键盘开发资料.rar"压缩包中,主要适用于那些进行嵌入式系统开发的工程师。在深入探讨其开发...
斑马ZT510打印机驱动文件
斑马打印机ZT210是一款专业的工业级条形码和标签打印机,广泛应用于物流、零售、医疗等行业的标签制作。以下是对如何设置和使用斑马ZT210打印机的详细步骤: 首先,我们需要安装电脑驱动。双击下载好的驱动程序文件...
通过深入学习这份手册,不仅可以理解ZT598密码键盘的工作原理,还能有效地编写出与之交互的程序,实现安全、高效的数据交换。在实际应用中,根据具体需求,可能还需要结合硬件手册和软件开发工具包(SDK)来完成整个...
《ZT210 230加载介质和碳带...通过了解介质和碳带的选择、安装以及打印机的设置,用户可以充分利用这些设备,实现高效、高质的打印作业。视频资料的提供,更是为用户提供了方便的学习途径,使得操作过程更为直观易懂。
赠送jar包:zt-exec-1.9.jar; 赠送原API文档:zt-exec-1.9-javadoc.jar; 赠送源代码:zt-exec-1.9-sources.jar; 赠送Maven依赖信息文件:zt-exec-1.9.pom; 包含翻译后的API文档:zt-exec-1.9-javadoc-API文档-...
- 实现机械化超前支护:在巷道挖掘过程中,可以实现对前方煤层的预先支护,保障作业安全。 4. 应用效果: 在冀中能源峰峰集团新屯矿的应用实践中,ZT19600/25/50端头液压支架的使用使得生产作业更加安全、高效和...
斑马zt210是一款专为中国市场设计的工业条码打印机,非常适合不需要频繁更换标签的条码标签应用。这里给大家提供斑马zt210驱动下载,推荐有需要的用户下载安装。斑马zt210打印机优势:◆ 节省空间* 小巧紧凑和流线型...
而ZT-TR43系列参数设置软件就是为了确保这些LED设备能够根据用户需求进行个性化调整,实现最佳性能和效果。 该软件的核心功能在于LED的参数配置。这包括但不限于以下几个方面: 1. **亮度调节**:用户可以通过软件...
赠送jar包:zt-exec-1.9.jar; 赠送原API文档:zt-exec-1.9-javadoc.jar; 赠送源代码:zt-exec-1.9-sources.jar; 赠送Maven依赖信息文件:zt-exec-1.9.pom; 包含翻译后的API文档:zt-exec-1.9-javadoc-API文档-...