当前位置: 首页 > 后端技术 > PHP

行为验证码的验证类型详解

时间:2023-03-30 02:05:31 PHP

前言最近,行为验证码的开发经常会涉及到验证类型的相关内容。但是我用起来不是很熟练。闲暇之余,总结一下自己对行为验证码验证类型的理解。验证类型概述刷卡拼图创新行为验证,轻松一键完成拼图,极佳体验,秒过验证。简单高效,在保证极致用户体验的同时,抵御机器风险。适用于追求用户体验的场景。#生成背景图basemap1=Image.open(bg).convert("RGBA")#背景图ifbasemap1.size!=size:#需要裁剪或拉伸basemap1=Graphics.crop(basemap1,size[0],size[1])puzzle1=Image.open(url_absolute(img)).convert("RGBA")#方块图,mask#旋转角度ifrotate==2:angle=randint(0,360)elifrotate==1:angle=choice([0,90,180,270])else:angle=0#angle=45ifangle:puzzle1=puzzle1.rotate(angle,resample=Image.Resampling.BILINEAR)puzzle1.putalpha(ImageEnhance.Brightness(puzzle1.split()[3]).enhance(alpha))#设置透明度,在0-1之间#生成一个随机位置img_size=puzzle1.size#滑动图片大小spacing=0#滑动图片在底面上map位置周围的间距,暂时用0,小图片中的pattern本身有20px的边距#randompositionx=randint(img_size[0]+spacing,size[0]-img_size[0]-spacing)y=randint(间距,尺寸[1]-img_size[1]-间距)basemap1.paste(puzzle1,(x,y),puzzle1)#copy#blockslidingmap#basemap2=Image.open(url_absolute(bg)).convert("RGBA")basemap2=Image.open(bg).convert("RGBA")ifbasemap2.size!=size:#需要裁剪或拉伸basemap2=Graphics.crop(basemap2,size[0],size[1])puzzle2=Image.open(url_absolute(img)).convert("RGBA")ifangle:puzzle2=puzzle2.rotate(angle,resample=Image.Resampling.BILINEAR)#旋转basemap2=basemap2.crop((x,y,x+img_size[0],y+img_size[1]))#剪切puzzle2.paste(basemap2,(0,0),puzzle2)#替换长条滑块strip=Image.new('RGBA',(img_size[0],size[1]),(255,255,255,0))strip.paste(puz??zle2,(0,y),puzzle2)#复制文字点击顺序点击图片中的文字,新的行为验证,安全性高,保证验证安全,增加难度机器识别,保证真实用户的可读性,适用于对安全性要求高的业务场景。defrandom_character(self,length=None,type=[0,1,2,3],repeat=False):"""生成随机字符:paramlength:生成字符的长度,几个字符:paramtype:[0]numbers,[1]大写字母,[2]小写字母,[3]特殊字符:paramrepeat:是否允许重复字符:return[("A",1,"大写字母"),("8",0,"number"),("a",2,"小写字母"),("",3,"高跟鞋")...]"""iflengthisNone:length=self.str_count#length=10#type=[0]string="".join(dict([(key,{0:"2345678923456789",1:"ABCDEFGHJKLMNQRTY",2:"abcdefghijkmnqrty",3:"",}[key])forkeyintype]).values())r=[]foriinrange(length):ifrepeat:#允许重复s=choice(string)t=Inference.char_type(s)r.append((s,t[0],t[1]))else:anti=0#防止无限循环,允许字符在尝试一定次数后重复whileTrue:anti+=1s=choice(string)t=Inference.char_type(s)st="".join([it[0]foritinr])如果s不在st或anti>30:r.append((s,t[0],t[1]))break#用图形字符替换n个字母if3intype:index=sample([iforiinrange(length)],randint(0,length))#一组随机的索引值:[0,3,1]icon_char=sample(self.icon_str,len(index))#随机取出n组特殊字符x=0foriinindex:#r=Inference.char_replace(r,i,icon_char[x][1])r[i]=(icon_char[x][1],3,icon_char[x][2])x+=1returnr点击词序根据中文语义,点击图片顺序,结合语义理解能力行为痕迹适用于对安全性要求高的业务场景。下面举例来说说干扰点和干扰线的制作:#Noiselineforiinrange(line_count):x1=randint(0,size[0])x2=randint(0,size[0])y1=randint(0,size[1])y2=randint(0,size[1])draw.line((x1,y1,x2,y2),fill=Word.get_random_color())#范围内的噪声(point_count):draw.point([randint(0,size[0]),randint(0,size[1])],fill=Word.get_random_color())x=randint(0,size[0])y=randint(0,size[1])draw.arc((x,y,x+4,y+4),0,90,fill=Word.get_random_color())字体识别点击不同字体的文字其他字符的字体,用户只需一键安全验证。适用于对安全性要求极高的业务场景。#字体识别iftypein(10,11,12):#789生成成语/固定字符str_count=1str_inter=numeric(str_inter,2,20)#干扰字符不能小于2v_font=sample(ttf,2)#随机选择两种字体string=[]foriinrange(str_count+str_inter):iftypein(10,11,12):#字体识别,只使用两种字体font_file=v_font[0]ifi==0elsev_font[1]else:#随机字体font_file=choice(ttf)font=ImageFont.truetype(url_absolute(font_file),size=font_size)#成语/使用固定字符,前n个字符使用成语字符random_char=idiom[i:i+1]ifidiomelse""#随机字符串和补充固定字符添加干扰字符ifrandom_char=="":head=randint(0xb0,0xf7)body=randint(0xa1,0xfe)random_char=bytes.fromhex(f'{head:x}{body:x}').decode("gb18030")#print(random_char,font_file)#随机位置anti=0#防止字体设置过大或图片设置过大small,导致死循环,允许字符在尝试一定次数后重叠whileTrue:#防止文本重叠anti+=1x=randint(0,size[0]-font_size)y=randint(0,size[1]-font_size)find=Trueforsinstring:ifabs(x-s[1])20:break#创建文本图像,可以旋转str_bg=Image.new("RGBA",(font_size,font_size),(255,255,255,0))#文字使用空白层str_draw=ImageDraw.Draw(str_bg)str_draw.text((0,0),random_char,Word.get_random_color(),font=font)#添加文本angle=randint(-75,75)ifrotateelse0#Randomanglestr_bg=str_bg.rotate(angle,resample=Image.Resampling.BILINEAR,expand=0)#随机旋转basemap.paste(str_bg,(x,y),str_bg)#图像和文本合并#保存随机字符和位置string.append([random_char,x,y,-angle])#字符,x,y,angle(正负转换,切换成CSS顺时针旋转形式)空间推理根据提示点击相应元素逻辑解题能力结合图形符号等元素识别能力。适用于对安全性要求极高的业务场景。下面是一些验证方法的例子:defsend_color2differ(self):"""请点击不同颜色的字符"""color=self.color_name(2)#得到2组中文名称的颜色[('blue','#0000FF'),]data=[]foriinrange(self.str_count):#数据/图片上生成的数据data.append({"str":self.string[i][0],#字符内容"X":self.coord[i][0],#x位置"Y":self.coord[i][1],#y位置"color":color[0][1]ifi==0elsecolor[1][1],"angle":self.angle[i],"icon":Trueifself.string[i][1]==3elseFalse,#是否是图形字符})#hint/Operationtexthint=f'Pleaseclickona{self.string[0][2]}'withdifferentcolors'str=[(数据[0]["str"],data[0]["X"],data[0]["Y"],data[0]["angle"]),]return{"data":数据,"海峡;:str,"hint":hint}defsend_color2capital(self):"""请点击蓝色字母对应的大写"""direc=choice([1,2])#随机方法,大写转小写/小写转大写color=self.color_name()#得到n组中文名称的颜色[('blue','#0000FF'),]self.string=self.random_character(type=[direc])data=[]foriinrange(self.str_count):#数据/图片上生成的数据data.append({"str":self.string[i][0],#字符内容"X":self.coord[i][0],#x位置"Y":self.coord[i][1],#y位置"color":color[i][1],"angle":self.angle[i],"icon":Trueifself.string[i][1]==3elseFalse,#是否是图形字符})data[0]["str"]=data[1]["str"].swapcase()#提示/操作描述文字hint=f'请点击{"capital"i>对应{color[0][0]}字母fdirect==1else"lowercase"}'str=[(data[1]["str"],data[1]["X"],data[1]["Y"],数据[1]["angle"]),]return{"data":data,"str":str,"hint":hint}综上所述,以上就是本文的全部内容。相关代码我已经放在了Github上,https://github.com/KgCaptcha,这里我做了一个示例:https://www.kgcaptcha.com/demo/