最近滑动验证码在很多网站逐步流行起来,一方面对用户体验来说,比较新颖,操作简单,另一方面相对图形验证码来说,安全性并没有很大的降低。当然到目前为止,没有绝对的安全验证,只是不断增加攻击者的绕过成本。

接下来分析下滑动验证码的核心流程:

  1. 后端随机生成抠图和带有抠图阴影的背景图片,后台保存随机抠图位置坐标
  2. 前端实现滑动交互,将抠图拼在抠图阴影之上,获取到用户滑动距离值,比如以下示例
  3. 前端将用户滑动距离值传入后端,后端校验误差是否在容许范围内。

这里单纯校验用户滑动距离是最基本的校验,出于更高的安全考虑,可能还会考虑用户滑动的整个轨迹,用户在当前页面的访问行为等。这些可以很复杂,甚至借助到用户行为数据分析模型,最终的目标都是增加非法的模拟和绕过的难度。这些有机会可以再归纳总结常用到的方法,本文重点集中在如何基于Java来一步步实现滑动验证码的生成。

可以看到,滑动图形验证码,重要有两个图片组成,抠块和带有抠块阴影的原图,这里面有两个重要特性保证被暴力破解的难度:抠块的形状随机和抠块所在原图的位置随机。这样就可以在有限的图集中制造出随机的、无规律可寻的抠图和原图的配对。

用代码如何从一张大图中抠出一个有特定随机形状的小图呢?

第一步,先确定一个抠出图的轮廓,方便后续真正开始执行图片处理操作

图片是有像素组成,每个像素点对应一种颜色,颜色可以用RGB形式表示,外加一个透明度,把一张图理解成一个平面图形,左上角为原点,向右x轴,向下y轴,一个坐标值对应该位置像素点的颜色,这样就可以把一张图转换成一个二维数组。基于这个考虑,轮廓也用二维数组来表示,轮廓内元素值为1,轮廓外元素值对应0。

这时候就要想这个轮廓形状怎么生成了。有坐标系、有矩形、有圆形,没错,用到数学的图形函数。典型用到一个圆的函数方程和矩形的边线的函数,类似:

(x-a)²+(y-b)²=r²中,有三个参数a、b、r,即圆心坐标为(a,b),半径r。这些将抠图放在上文描述的坐标系上很容易就图算出来具体的值。

示例代码如下:

private int[][] getBlockData() {
int[][] data = new int[targetLength][targetWidth];
double x2 = targetLength-circleR-2;
//随机生成圆的位置
double h1 = circleR + Math.random() * (targetWidth-3*circleR-r1);
double po = circleR*circleR; double xbegin = targetLength-circleR-r1;
double ybegin = targetWidth-circleR-r1; for (int i = 0; i < targetLength; i++) {
for (int j = 0; j < targetWidth; j++) {
//右边○
double d3 = Math.pow(i - x2,2) + Math.pow(j - h1,2); if (d1 <= po
|| (j >= ybegin && d2 >= po)
|| (i >= xbegin && d3 >= po)
) {
data[i][j] = 0; } else {
data[i][j] = 1;
}
}
}
return data;
}

第二步,有这个轮廓后就可以依据这个二维数组的值来判定抠图并在原图上抠图位置处加阴影。

操作如下:

private void cutByTemplate(BufferedImage oriImage,BufferedImage targetImage, int[][] templateImage, int x,
int y){
for (int i = 0; i < targetLength; i++) {
for (int j = 0; j < targetWidth; j++) {
int rgb = templateImage[i][j];
// 原图中对应位置变色处理 int rgb_ori = oriImage.getRGB(x + i, y + j); if (rgb == 1) {
//抠图上复制对应颜色值
targetImage.setRGB(i, y + j, rgb_ori);
int r = (0xff & rgb_ori);
int g = (0xff & (rgb_ori >> 8));
int b = (0xff & (rgb_ori >> 16)));
rgb_ori = r + (g << 8) + (b << 16) + (200 << 24);
//原图对应位置颜色变化
oriImage.setRGB(x + i, y + j, rgb_ori);
}
}
}
}

经过前面两步后,就得到了抠图和带抠图阴影的原图。为增加混淆和提高网络加载效果,还需要对图片做进一步处理。一般有两件事需要做,一对图片做模糊处理增加机器识别难度,二做适当同质量压缩。模糊处理很容易想到高斯模糊,原理很好理解,大家可以去google了解下。具体到Java里面的实现,有很多版本,现在不借助任何第三方jar,提供一个示例:

public static ConvolveOp getGaussianBlurFilter(int radius,
boolean horizontal) {
if (radius < 1) {
throw new IllegalArgumentException("Radius must be >= 1");
} int size = radius * 2 + 1;
float[] data = new float[size]; float sigma = radius / 3.0f;
float twoSigmaSquare = 2.0f * sigma * sigma;
float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
float total = 0.0f; for (int i = -radius; i <= radius; i++) {
float distance = i * i;
int index = i + radius;
data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
total += data[index];
} for (int i = 0; i < data.length; i++) {
data[i] /= total;
} Kernel kernel = null;
if (horizontal) {
kernel = new Kernel(size, 1, data);
} else {
kernel = new Kernel(1, size, data);
}
return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
} public static void simpleBlur(BufferedImage src,BufferedImage dest) {
BufferedImageOp op = getGaussianBlurFilter(2,false);
op.filter(src, dest);
}

经测试模糊效果很不错。另外是图片压缩,也不借助任何第三方工具,做同质压缩。

 public static byte[] fromBufferedImage2(BufferedImage img,String imagType) throws IOException {
bos.reset();
// 得到指定Format图片的writer
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(imagType);
ImageWriter writer = (ImageWriter) iter.next(); // 得到指定writer的输出参数设置(ImageWriteParam )
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩
iwp.setCompressionQuality(1f); // 设置压缩质量参数 iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED); ColorModel colorModel = ColorModel.getRGBdefault();
// 指定压缩时使用的色彩模式
iwp.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel,
colorModel.createCompatibleSampleModel(16, 16))); writer.setOutput(ImageIO
.createImageOutputStream(bos));
IIOImage iIamge = new IIOImage(img, null, null);
writer.write(null, iIamge, iwp); byte[] d = bos.toByteArray();
return d;
}

至此,滑动验证码核心的代码处理流程已全部结束,这里面有很多细节可以不断打磨优化,让滑动体验可以变得更好。希望可以帮助到某些准备自己构建滑动验证码的同学。

以上代码实现都非常的精炼,一方面为了保证性能,另一方面好理解。另外由于各方面原因也不便引入过多细节,如果疑问,可留言交流。经测试,该生成滑动图形的流程响应时间可以控制在20ms左右,如果原图分辨率在300px*150px以下,可以到10ms左右,在可接受范围内。如果有更高效的方式,希望多多指教。

https://my.oschina.net/yaohonv/blog/1604185

一步步实现滑动验证码,Java图片处理关键代码的更多相关文章

  1. Python——破解极验滑动验证码

    极验滑动验证码 以上图片是最典型的要属于极验滑动认证了,极验官网:http://www.geetest.com/. 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家 ...

  2. Python 破解极验滑动验证码

    Python 破解极验滑动验证码 测试开发社区  1周前 阅读目录 极验滑动验证码 实现 位移移动需要的基础知识 对比两张图片,找出缺口 获得图片 按照位移移动 详细代码 回到顶部 极验滑动验证码 以 ...

  3. SpringCloud微服务实战——搭建企业级开发框架(二十四):集成行为验证码和图片验证码实现登录功能

    随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替图片验证码.GitEgg-Cloud集成了开源行为验证码组件和图片验证码,并在系统中添加可配置 ...

  4. selenium+java破解极验滑动验证码

    摘要 分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码. 人工验证的过程 打开威锋网注册页面(https://passport.feng.com/?r=user/r ...

  5. selenium+java破解极验滑动验证码的示例代码

    转自: https://www.jianshu.com/p/1466f1ba3275 selenium+java破解极验滑动验证码 卧颜沉默 关注 2017.08.15 20:07* 字数 3085  ...

  6. selenium+java破解滑动验证码

    2019-04-16更新 修复极验页面改版,这次采用极验官方的demo地址:https://www.geetest.com/demo/slide-bind.html 截止2019-04-16,极验和腾 ...

  7. selenium处理极验滑动验证码

    要爬取一个网站遇到了极验的验证码,这周都在想着怎么破解这个,网上搜了好多知乎上看到有人问了这问题https://www.zhihu.com/question/28833985,我按照这思路去大概实现了 ...

  8. Atitit.java图片图像处理attilax总结

    Atitit.java图片图像处理attilax总结 BufferedImage extends java.awt.Image 获取图像像素点 image.getRGB(i, lineIndex); ...

  9. Atitit.java图片图像处理attilax总结  BufferedImage extends java.awt.Image获取图像像素点image.getRGB(i, lineIndex); 图片剪辑/AtiPlatf_cms/src/com/attilax/img/imgx.javacutImage图片处理titit 判断判断一张图片是否包含另一张小图片 atitit 图片去噪算法的原理与

    Atitit.java图片图像处理attilax总结 BufferedImage extends java.awt.Image 获取图像像素点 image.getRGB(i, lineIndex); ...

随机推荐

  1. Jarvis OJ - [XMAN]level3 - Writeup——ret2libc尝试

    这次除了elf程序还附带一个动态链接库 先看一下,很一般的保护 思路分析 在ida中查看,可以确定通过read函数输入buf进行溢出,但是并没有看到合适的目标函数 但是用ida打开附带的链接库,可以看 ...

  2. jquery on()动态绑定元素的的点击事件无反应的问题记录

    1.jquery使用版本:v2.0 2.重现代码: html <table class="table"> <thead> <tr> <th ...

  3. hdu 1885 Key Task(bfs)

    http://acm.hdu.edu.cn/showproblem.php?pid=1885 再贴一个链接http://blog.csdn.net/u013081425/article/details ...

  4. 利用反射操作bean的属性和方法

    今天在开发中碰到这样一个场景:当请求添加项目下的目录时,传过来的是一个IndexModel,这个Model里有关于这个目录字段的详细信息,包括基础报表,实时,漏斗等信息(这些字段类型都是boolean ...

  5. Eclipse 插件安装、升级和卸载的方法

    Eclipse 的插件可以装在内部,也可以装在外部,装在内部的方法很简单:把插件的features和plugins目录copy到eclipse的安装目录即可. eclipse和其插件升级比较频繁,用过 ...

  6. css自动添加浏览器兼容前缀 autoprefixer设置

    Autoprefixer设置: preferences>key Bindings-Users {"keys":["ctrl+alt+x"],"c ...

  7. 浅析JavaScript的字符串查找函数:indexOf和search

    语法 ①indexOf:方法可返回某个指定的字符串值在长字符串中首次出现的位置.如果被查找字符串没有找到,返回-1. indexOf 说明:该方法将从头到尾地检索字符串 stringObject,看它 ...

  8. Cenos 6.5上的subverion的yum配置笔记

    Subversion在CenOS 6.5上的安装配置 1.安装 yum install subversion 2.配置   #创建目录   mkdir /opt/svn   #创建版本库   svna ...

  9. webpack加载多级依赖时css、html文件不能正确resolve的问题

    在使用webpack+avalon以及avalon的mmRouter做SPA的时候,碰到一个困扰数周的问题:webpack加载多级依赖时出现了css文件和模板(html)文件不能正确resolve.原 ...

  10. JavaScript 中 闭包 的详解

    闭包是什么 在 JavaScript 中,闭包是一个让人很难弄懂的概念.ECMAScript 中给闭包的定义是:闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量. ...