参考源码https://github.com/binwind8/tncode

演示地址http://aso.39gs.com/tncode/index.html

参考上述源码,实现了通过接口访问,验证滑动验证码功能。

原理:

后台生成滑动验证码,记录小图偏移量。然后前台用户滑动图片,通过js传递偏移量到后台,如果与后台记录偏移量相同或者在误差允许范围内,则代码验证通过。

偏移量可以记录X轴,也可以记录Y轴
验证码X轴 = 浏览器在电脑屏上的X轴 + 验证码在浏览器中的X轴
验证码Y轴 = 浏览器在电脑屏上的Y轴 + 验证码在浏览器中的Y轴

Demo

本示例通过记录X轴变量实现。

Api接口一

获取图片

1
2
3
4
5
6
/**
* 获取图片校验码接口
*/
public function getVerificationImage(){
D('VerificationCode')->make();
}

Api接口二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 图片校验码校验接口
*/
public function verificationImage(){
//偏移量
$offset = I('offset', 0, 'trim,intval');

$check = D('VerificationCode')->verification($offset);
if($check){
success_json();
}else{
error_json('验证错误');
}
}

Model核心文件

Model文件VerificationCode.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<?php
/**
* Class TnCode
* tncode 1.2 author:weiyingbin email:277612909@qq.com
* @ object webiste: http://www.39gs.com/archive/259.html
* @ https://github.com/binwind8/tncode
*/

namespace Common\Model;

class VerificationCodeModel extends \Think\Model
{
protected $autoCheckFields = false;
protected $tableName = "tw_job";

var $im = null;
var $im_fullbg = null;
var $im_bg = null;
var $im_slide = null;
var $bg_width = 240;
var $bg_height = 150;
var $mark_width = 50;
var $mark_height = 50;
var $bg_num = 6;
var $_x = 0;
var $_y = 0;
//容错象素 越大体验越好,越小破解难道越高
var $_fault = 3;

/**
* @var 验证码缓存键
*/
private $cacheCode = 'verify_code_key';
/**
* 错误次数
* @var int
*/
private $cacheCodeErr = 0;

function __construct(){
error_reporting(0);
}

public function make(){
$this->_init();
$this->_createSlide();
$this->_createBg();
$this->_merge();
$this->_imgout();
$this->_destroy();
}

public function verification($offset=''){
$right = $this->cacheInfo($this->cacheCode);
if(!$right || !$offset){
return false;
}

$ret = abs($right - $offset) <= $this->_fault;
if(!$ret){
//错误次数
$errorNum = $this->cacheInfo($this->cacheCodeErr);
$this->cacheInfo($this->cacheCodeErr, $errorNum + 1);
//错误10次必须刷新
if($errorNum > 9){
$this->cacheInfo($this->cacheCode, null);
}
return false;
}
return true;
}

private function cacheInfo($key, $val = null, $expire = 180){
//可以使用多种方式缓存,session,数据库,redis等
return D('Cache')->cache($key,$val,$expire);
}

private function _init(){
$bg = mt_rand(1,$this->bg_num);
$file_bg = './Public/images/verification/bg/'.$bg.'.png';
$this->im_fullbg = imagecreatefrompng($file_bg);
$this->im_bg = imagecreatetruecolor($this->bg_width, $this->bg_height);
imagecopy($this->im_bg,$this->im_fullbg,0,0,0,0,$this->bg_width, $this->bg_height);
$this->im_slide = imagecreatetruecolor($this->mark_width, $this->bg_height);
$value = $this->_x = mt_rand(50,$this->bg_width-$this->mark_width-1);
$this->_y = mt_rand(0,$this->bg_height-$this->mark_height-1);

$this->cacheInfo($this->cacheCode, $value);
$this->cacheInfo($this->cacheCodeErr, 0);
}

private function _imgout(){
if(function_exists('imagewebp')){//优先webp格式,超高压缩率
$type = 'webp';
$quality = 40;//图片质量 0-100
}else{
$type = 'png';
$quality = 7;//图片质量 0-9
}
header('Content-Type: image/'.$type);
$func = "image".$type;
$func($this->im,null,$quality);
}

private function _merge(){
$this->im = imagecreatetruecolor($this->bg_width, $this->bg_height*3);
imagecopy($this->im, $this->im_bg,0, 0 , 0, 0, $this->bg_width, $this->bg_height);
imagecopy($this->im, $this->im_slide,0, $this->bg_height , 0, 0, $this->mark_width, $this->bg_height);
imagecopy($this->im, $this->im_fullbg,0, $this->bg_height*2 , 0, 0, $this->bg_width, $this->bg_height);
imagecolortransparent($this->im,0);//16777215
}

private function _createBg(){
$file_mark = './Public/images/verification/img/mark.png';
$im = imagecreatefrompng($file_mark);
header('Content-Type: image/png');
//imagealphablending( $im, true);
imagecolortransparent($im,0);//16777215
//imagepng($im);exit;
imagecopy($this->im_bg, $im, $this->_x, $this->_y , 0 , 0 , $this->mark_width, $this->mark_height);
imagedestroy($im);
}

private function _createSlide(){
$file_mark = './Public/images/verification/img/mark2.png';
$img_mark = imagecreatefrompng($file_mark);
imagecopy($this->im_slide, $this->im_fullbg,0, $this->_y , $this->_x, $this->_y, $this->mark_width, $this->mark_height);
imagecopy($this->im_slide, $img_mark,0, $this->_y , 0, 0, $this->mark_width, $this->mark_height);
imagecolortransparent($this->im_slide,0);//16777215
//header('Content-Type: image/png');
//imagepng($this->im_slide);exit;
imagedestroy($img_mark);
}

private function _destroy(){
imagedestroy($this->im);
imagedestroy($this->im_fullbg);
imagedestroy($this->im_bg);
imagedestroy($this->im_slide);
}
}

优化

后台可以针对用户产生的行为轨迹数据进行机器学习建模,结合访问频率、地理位置、历史记录等多个维度信息。这样能够增加破解难度。

也可以使用专用Api服务商,如网易云验证码