一步步实现滑动验证码,Java图片处理关键代码
最近滑动验证码在很多网站逐步流行起来,一方面对用户体验来说,比较新颖,操作简单,另一方面相对图形验证码来说,安全性并没有很大的降低。当然到目前为止,没有绝对的安全验证,只是不断增加攻击者的绕过成本。
接下来分析下滑动验证码的核心流程:
- 后端随机生成抠图和带有抠图阴影的背景图片,后台保存随机抠图位置坐标
- 前端实现滑动交互,将抠图拼在抠图阴影之上,获取到用户滑动距离值,比如以下示例
- 前端将用户滑动距离值传入后端,后端校验误差是否在容许范围内。
这里单纯校验用户滑动距离是最基本的校验,出于更高的安全考虑,可能还会考虑用户滑动的整个轨迹,用户在当前页面的访问行为等。这些可以很复杂,甚至借助到用户行为数据分析模型,最终的目标都是增加非法的模拟和绕过的难度。这些有机会可以再归纳总结常用到的方法,本文重点集中在如何基于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图片处理关键代码的更多相关文章
- Python——破解极验滑动验证码
极验滑动验证码 以上图片是最典型的要属于极验滑动认证了,极验官网:http://www.geetest.com/. 现在极验验证码已经更新到了 3.0 版本,截至 2017 年 7 月全球已有十六万家 ...
- Python 破解极验滑动验证码
Python 破解极验滑动验证码 测试开发社区 1周前 阅读目录 极验滑动验证码 实现 位移移动需要的基础知识 对比两张图片,找出缺口 获得图片 按照位移移动 详细代码 回到顶部 极验滑动验证码 以 ...
- SpringCloud微服务实战——搭建企业级开发框架(二十四):集成行为验证码和图片验证码实现登录功能
随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替图片验证码.GitEgg-Cloud集成了开源行为验证码组件和图片验证码,并在系统中添加可配置 ...
- selenium+java破解极验滑动验证码
摘要 分析验证码素材图片混淆原理,并采用selenium模拟人拖动滑块过程,进而破解验证码. 人工验证的过程 打开威锋网注册页面(https://passport.feng.com/?r=user/r ...
- selenium+java破解极验滑动验证码的示例代码
转自: https://www.jianshu.com/p/1466f1ba3275 selenium+java破解极验滑动验证码 卧颜沉默 关注 2017.08.15 20:07* 字数 3085 ...
- selenium+java破解滑动验证码
2019-04-16更新 修复极验页面改版,这次采用极验官方的demo地址:https://www.geetest.com/demo/slide-bind.html 截止2019-04-16,极验和腾 ...
- selenium处理极验滑动验证码
要爬取一个网站遇到了极验的验证码,这周都在想着怎么破解这个,网上搜了好多知乎上看到有人问了这问题https://www.zhihu.com/question/28833985,我按照这思路去大概实现了 ...
- Atitit.java图片图像处理attilax总结
Atitit.java图片图像处理attilax总结 BufferedImage extends java.awt.Image 获取图像像素点 image.getRGB(i, lineIndex); ...
- 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); ...
随机推荐
- javascript设计模式——职责链模式
前面的话 职责链模式的定义是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.职责链模式的名字非常形象,一 ...
- webpack安装配置
webpack安装 1.安装之前你必须要安装node.js,如果你没安装可以在node.js网去下载node.js 2.全局安装webpack,打开cmd输入npm install webpack - ...
- C++ list forward_list
list,forward_list list:双向链表 forward_list:单向链表 在任何位置添加元素,删除元素都很快,但随机访问元素则很慢 声明和初始化 list<T> l; l ...
- Oracle在本地调试成功读取数据,但是把代码放到服务器读不出数据的解决方法。
用MVC EF框架开发项目,数据库用的是Oracle,本地调试的时候一切正常,但是把代码编译之后放到服务器就会读不出数据. 原因:本地调试环境与服务器环境不一致. 办法:在服务器上装ODT.NET组件 ...
- ios应用程序国际化
1.程序名称国际化: 在Xcode中新建项目后,能够在project的info选项卡中找到Localization的项目,能够加入应用程序须要支持的国际语言. 回到项目中能够发如今InfoPlist. ...
- 【剑指offer】扑克牌的顺子
个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想測測自己的手气,看看能不能抽到顺子,假设抽到的话,他决定去买体育彩票,嘿嘿! ."红心A,黑桃3,小王,大王,方片 ...
- myeclipse配置SVN插件
方法一:link安装 安装subclipse, MyEclipse SVN插件 1.从官网下载最新的site-1.x.x.zip文件,网址是:folderID=2240" target= ...
- 002Java概述
1Sun(Stanford University Network )公司1995年推出的高级编程语言 2.面向Internet的编程语言 3.已经成为web应用程序的首选开发语言 4.完全面向对象简单 ...
- 自学Python2.2-基本数据类型-列表list(object)
Python List方法总结 一. 列表简介: 列表是序列对象,可包含任意的Python数据信息,如字符串.数字.列表.元组等 列表的数据是可变的,我们可通过对象方法对列表中的数据进行增加.修改 ...
- Selenium Python 安装指导
最近无聊.又重新装了个selenium 果然时代变了.安装的时候的方法和以前不太一样了.因此觉得有必要单列出来加以说明 另外备注:测试小伙伴们.安装此类工具报错.尝试以下两个方案之一: 1.请转sta ...