读书人

《转》利用JavaScript破译验证码

发布时间: 2012-10-09 10:21:45 作者: rapoo

《转》利用JavaScript破解验证码

 如今,基于web的应用越来越普及,随之而来的安全威胁也越来越大,近日网上惊现可以破解验证码的JavaScript脚本,可以轻松搞定流行的验证机制CAPTCHA。

????? function?convert_grey(image_data){
  for?(var?x?=?0;?x?<?image_data.width;?x++){
  for?(var?y?=?0;?y?<?image_data.height;?y++){
  var?i?=?x*4+y*4*image_data.width;
  var?luma?=?Math.floor(image_data.data[i]?*?299/1000?+
  image_data.data[i+1]?*?587/1000?+
  image_data.data[i+2]?*?114/1000);
  image_data.data[i]?=?luma;
  image_data.data[i+1]?=?luma;
  image_data.data[i+2]?=?luma;
  image_data.data[i+3]?=?255;
  }
  }
  }

?

  然后,将画布分成三个单独的像素矩阵,每个矩阵包含一个字符。这一步实现起来非常容易,因为每个字符都使用一种单独的颜色,所以通过颜色就可以将其区分开来。

?

????? filter(image_data[0],?105);
  filter(image_data[1],?120);
  filter(image_data[2],?135);
  function?filter(image_data,?colour){
  for?(var?x?=?0;?x?<?image_data.width;?x++){
  for?(var?y?=?0;?y?<?image_data.height;?y++){
  var?i?=?x*4+y*4*image_data.width;
  //?Turn?all?the?pixels?of?the?certain?colour?to?white
  if?(image_data.data[i]?==?colour)?{
  image_data.data[i]?=?255;
  image_data.data[i+1]?=?255;
  image_data.data[i+2]?=?255;
  //?Everything?else?to?black
  }?else?{
  image_data.data[i]?=?0;
  image_data.data[i+1]?=?0;
  image_data.data[i+2]?=?0;
  }
  }
  }
  }

?

  最终,所有无关的干扰像素都被剔除出去。为此,可以先查找那些前面或者后面被黑色(未匹配的)像素围绕的白色(匹配过的)像素,然后将匹配过的像素删除即可。

?

????? var?i?=?x*4+y*4*image_data.width;
  var?above?=?x*4+(y-1)*4*image_data.width;
  var?below?=?x*4+(y+1)*4*image_data.width;
  if?(image_data.data[i]?==?255?&&
  image_data.data[above]?==?0?&&
  image_data.data[below]?==?0)?{
  image_data.data[i]?=?0;
  image_data.data[i+1]?=?0;
  image_data.data[i+2]?=?0;
  }

?

  现在我们已经得到了字符的大约图形,但在将其载入神经网络之前,脚本还会进一步对它进行必要的边缘检测。脚本会寻找图形最左、右、上、下方的像素,并将其转化为一个矩形,接着把矩形重新转换为一个20*25像素的矩阵。

?

????? cropped_canvas.getContext("2d").fillRect(0,?0,?20,?25);
  var?edges?=?find_edges(image_data[i]);
  cropped_canvas.getContext("2d").drawImage(canvas,?edges[0],?edges[1],
  edges[2]-edges[0],?edges[3]-edges[1],?0,?0,
  edges[2]-edges[0],?edges[3]-edges[1]);
  image_data[i]?=?cropped_canvas.getContext("2d").getImageData(0,?0,
  cropped_canvas.width,?cropped_canvas.height);

?

  经过上面的处理,我们得到了什么呢? 一个20*25的矩阵,其中包含单个矩形,其中填由黑白色。真是太好了!

  然后,会对这个矩形做进一步的简化。我们策略性地从矩阵中提取一些点,作为“光感受器”,这些光感受器将输送到神经网络。举例而言,某个光感受器具体对应的可能是位于9*6位置像素,有像素或者没有像素。脚本会提取一系列这样的状态(远少于对 20*25矩阵整个计算的次数——只提取64种状态),并将这些状态送入神经网络。

  您可能要问,为什么不直接对像素进行比较?有必要使用神经网络吗?问题的关键在于,我们要去掉那些模棱两可的情况。如果您试过前面的演示就会发现,直接进行像素比较比通过神经网络比较,更容易出错,尽管出错的时候不多。但我们必须承认,对于大部分用户来说,直接的像素比较应该已经够用了。

  下一步就是尝试猜字母了。神经网络中导入了64个布尔值(由其中的一个字符图像获取而来),同时包含一系列预先计算好的数据。神经网络的理念之一,就是我们希望得的结果事先就是知道的,所以我们可以针对结果对神经网络进行相关的训练。脚本作者可以多次运行脚本,并收集了一系列最佳评分,这些评分能帮助倒推出产生它们的那些值,从而帮神经网络猜出答案,除此之外,这些评分没有任何特殊意义。

  当神经网络对验证码中一个字母对应的64个布尔值进行计算以后,和一个预先计算好的字母表相比较,然后为和每个字母的匹配都给出一个分数。(最后的结果可能类似:98%的可能是字母A,36%的可能是字母B等。)

  当对验证码中的三个字母都经过处理以后,最终的结果也就出来了。需要注意的是,该脚本无法达到100%正确性(不知道如果在开始的时候不将字母转换成矩形,是不是可以提高评分的精度),但这已经相当好了,至少对于当前的用途来说是这样。而且所有的操作都是在基于标准的客户端技术实现的浏览器中完成的!

  补充说明一下,这个脚本应该算是一个特例吧,这项技术可能会很好的工作在在其它简陋的验证码上,但对于复杂的验证码来说,就有点鞭长莫及了(尤其是这种基于客户端的分析)。但愿有更多人能从这个项目中受到启发而开发出更奇妙的东西来,因为它的潜力实在是太大了。

读书人网 >JavaScript

热点推荐