阿克苏网站开发,牛魔王网站建设,武昌网站建设制作,公司网站二维码生成器前言 
由于网站注册入口容易被黑客攻击#xff0c;存在如下安全问题#xff1a; 
1. 暴力破解密码#xff0c;造成用户信息泄露 
2. 短信盗刷的安全问题#xff0c;影响业务及导致用户投诉 
3. 带来经济损失#xff0c;尤其是后付费客户#xff0c;风险巨大#xff0c;造…前言 
由于网站注册入口容易被黑客攻击存在如下安全问题 
1. 暴力破解密码造成用户信息泄露 
2. 短信盗刷的安全问题影响业务及导致用户投诉 
3. 带来经济损失尤其是后付费客户风险巨大造成亏损无底洞 所以大部分网站及App 都采取图形验证码或滑动验证码等交互解决方案 但在机器学习能力提高的当下连百度这样的大厂都遭受攻击导致点名批评 图形验证及交互验证方式的安全性到底如何 请看具体分析 
一、 中国国际航空PC 注册入口 
简介中国国际航空股份有限公司简称“国航”英文名称为“Air China Limited”简称“Air China”其前身中国国际航空公司成立于1988年。根据国务院批准通过的《民航体制改革方案》2002年10月中国国际航空公司联合中国航空总公司和中国西南航空公司成立了中国航空集团公司并以联合三方的航空运输资源为基础组建新的中国国际航空公司。2004年9月30日经国务院国有资产监督管理委员会批准作为中国航空集团控股的航空运输主业公司国航股份在北京正式成立。2004年12月15日中国国际航空股份有限公司在香港股票代码0753和伦敦交易代码AIRC成功上市。  二、 安全性分析报告 
中国国际航空自己研发的滑动验证码容易被模拟器绕过甚至逆向后暴力攻击滑动拼图识别率在 95% 以上。  
三、 测试方法 前端界面分析这是中国国际航空自己研发的滑动验证码网上没有现成的教学视频但形式都差不多难点:. 防模拟器鼠标物理鼠标和逻辑鼠标定位不一致判断措施解决思路为让JS 这部分代码失效或这采用 物理定位鼠标的部分目前采用的是物理鼠标的方式。 这次还是采用模拟器的方式关键点主要模拟器交互、距离识别和轨道算法3部分  
1. 模拟器交互部分 private final String INDEX_URL  https://www.airchina.com.cn/user/register?backUrl/entryPagelogin;Overridepublic RetEntity send(WebDriver driver, String areaCode, String phone) {try {RetEntity retEntity  new RetEntity();driver.get(INDEX_URL);// 输入手机号WebElement phoneElemet  driver.findElement(By.xpath(//input[placeholder手机号]));phoneElemet.sendKeys(phone);// 点击发送验证码按钮WebElement sendElemet  driver.findElement(By.xpath(//div/div/div[text()获取验证码]));if (sendElemet ! null)sendElemet.click();Thread.sleep(1000);WebElement gtElemet  ChromeDriverManager.waitElement(driver, By.xpath(//div/div[contains(text(),验证码已发送)]), 1);String gtInfo  (gtElemet ! null) ? gtElemet.getText() : null;boolean isSend  (gtInfo ! null  gtInfo.contains(验证码已发送));if (!isSend) {// pic 1 get bigWebElement bigImgElement  ChromeDriverManager.waitElement(driver, By.id(cpc_img), 20);String bigImgUrl  bigImgElement.getAttribute(src);byte[] bigBytes  GetImage.callJsByUrl(driver, bigImgUrl);int bigLen  (bigBytes ! null) ? bigBytes.length : 0;if (bigLen  100) {System.out.println(bigImgUrl  bigImgUrl  -bigLen  bigLen);return null;}// pic 2 get smallWebElement smallImgElement  driver.findElement(By.id(small_img));String smallSrc  smallImgElement.getAttribute(src);byte[] smallBytes  GetImage.callJsByUrl(driver, smallSrc);if (smallBytes  null) {System.out.println(smallBytes  smallBytes);return null;}String ckSum  GenChecksumUtil.genChecksum(bigBytes);MapString, Double openResult  openCv2.getOpenCvDistance(ckSum, bigBytes, smallBytes, Airchina, 1);if (openResult  null || openResult.size()  2) {System.out.println(ckSum  ckSum  -openResult  openResult);return null;}Double r  421.0 / 275;BigDecimal disD  new BigDecimal(openResult.get(minX) * r).setScale(0, BigDecimal.ROUND_HALF_UP);int distance  disD.intValue();ActionMove.RobotMove(777, 710, distance);System.out.println(distance  distance);Thread.sleep(1000);}gtElemet  ChromeDriverManager.waitElement(driver, By.xpath(//div/div[contains(text(),验证码已发送)]), 100);gtInfo  (gtElemet ! null) ? gtElemet.getText() : null;retEntity.setMsg(gtInfo);if (gtInfo ! null  gtInfo.contains(验证码已发送)) {retEntity.setRet(0);} else {System.out.println(gtInfo  gtInfo);}return retEntity;} catch (Exception e) {System.out.println(phone  phone  ,e  e.toString());for (StackTraceElement ele : e.getStackTrace()) {System.out.println(ele.toString());}return null;} finally {driver.manage().deleteAllCookies();}} 2. 距离识别 /*** * param ckSum* param bigBytes* param smallBytes* param factory* return { width, maxX }*/public MapString, Double getOpenCvDistance(String ckSum, byte bigBytes[], byte smallBytes[], String factory, int border) {try {String basePath  ConstTable.codePath  factory  /;File baseFile  new File(basePath);if (!baseFile.isDirectory()) {baseFile.mkdirs();}// 小图文件File smallFile  new File(basePath  ckSum  _s.png);FileUtils.writeByteArrayToFile(smallFile, smallBytes);// 大图文件File bigFile  new File(basePath  ckSum  _b.png);FileUtils.writeByteArrayToFile(bigFile, bigBytes);// 边框清理(去干扰)byte[] clearBoder  (border  0) ? ImageIOHelper.clearBoder(smallBytes, border) : smallBytes;File tpFile  new File(basePath  ckSum  _t.png);FileUtils.writeByteArrayToFile(tpFile, clearBoder);String resultFile  basePath  ckSum  _o.png;return getWidth(tpFile.getAbsolutePath(), bigFile.getAbsolutePath(), resultFile);} catch (Throwable e) {logger.error(getMoveDistance() ckSum  ckSum     e.toString());for (StackTraceElement elment : e.getStackTrace()) {logger.error(elment.toString());}return null;}}/*** Open Cv 图片模板匹配* * param smallPath*            模板图片路径* param bgPath*            目标图片路径* return { width, maxX }*/public MapString, Double getWidth(String smallPath, String bgPath, String resultFile) {try {Rect rectCrop  clearWhite(smallPath);Mat g_tem  Imgcodecs.imread(smallPath);Mat clearMat  g_tem.submat(rectCrop);Mat cvt  new Mat();Imgproc.cvtColor(clearMat, cvt, Imgproc.COLOR_RGB2GRAY);Mat edgesSlide  new Mat();Imgproc.Canny(cvt, edgesSlide, threshold1, threshold2);Mat cvtSlide  new Mat();Imgproc.cvtColor(edgesSlide, cvtSlide, Imgproc.COLOR_GRAY2RGB);Imgcodecs.imwrite(smallPath, cvtSlide);Mat g_b  Imgcodecs.imread(bgPath);Mat edgesBg  new Mat();Imgproc.Canny(g_b, edgesBg, threshold1, threshold2);Mat cvtBg  new Mat();Imgproc.cvtColor(edgesBg, cvtBg, Imgproc.COLOR_GRAY2RGB);int result_rows  cvtBg.rows() - cvtSlide.rows()  1;int result_cols  cvtBg.cols() - cvtSlide.cols()  1;Mat g_result  new Mat(result_rows, result_cols, CvType.CV_32FC1);Imgproc.matchTemplate(cvtBg, cvtSlide, g_result, Imgproc.TM_CCOEFF_NORMED); // 归一化平方差匹配法// 归一化相关匹配法MinMaxLocResult minMaxLoc  Core.minMaxLoc(g_result);Point maxLoc  minMaxLoc.maxLoc;Imgproc.rectangle(cvtBg, maxLoc, new Point(maxLoc.x  cvtSlide.cols(), maxLoc.y  cvtSlide.rows()), new Scalar(0, 0, 255), 1);Imgcodecs.imwrite(resultFile, cvtBg);MapString, Double paramMap  new HashMapString, Double();paramMap.put(tpWidth, g_tem.cols() * 1.0);paramMap.put(bigWidth, cvtBg.cols() * 1.0);paramMap.put(width, cvtSlide.cols() * 1.0);paramMap.put(minX, maxLoc.x);paramMap.put(maxX, maxLoc.x  cvtSlide.cols());System.out.println(OpenCv2.getWidth()   paramMap.toString());return paramMap;} catch (Throwable e) {System.out.println(getWidth()   e.toString());logger.error(getWidth()   e.toString());for (StackTraceElement elment : e.getStackTrace()) {logger.error(elment.toString());}return null;}}public Rect clearWhite(String smallPath) {try {Mat matrix  Imgcodecs.imread(smallPath);int rows  matrix.rows();// height - yint cols  matrix.cols();// width - xSystem.out.println(OpenCv2.clearWhite()  rows  rows  ,cols  cols);Double rgb;double[] arr;int minX  255;int minY  255;int maxX  0;int maxY  0;Color c;for (int x  0; x  cols; x) {for (int y  0; y  rows; y) {arr  matrix.get(y, x);rgb  0.00;for (int i  0; i  3; i) {rgb  arr[i];}c  new Color(rgb.intValue());int b  c.getBlue();int r  c.getRed();int g  c.getGreen();int sum  r  g  b;if (sum  5) {if (x  minX)minX  x;else if (x  maxX)maxX  x;if (y  minY)minY  y;else if (y  maxY)maxY  y;}}}int boder  1;if (boder  0) {minX  (minX  boder) ? minX - boder : 0;maxX  (maxX  boder  cols) ? maxX  boder : cols;minY  (minY  boder) ? minY - boder : 0;maxY  (maxY  boder  rows) ? maxY  boder : rows;}int width  (maxX - minX);int height  (maxY - minY);System.out.println(openCv2 minX  minX  ,minY  minY  ,maxX  maxX  ,maxY  maxY  -width  width  ,height  height);Rect rectCrop  new Rect(minX, minY, width, height);return rectCrop;} catch (Throwable e) {StringBuffer er  new StringBuffer(clearWrite()   e.toString()  \n);for (StackTraceElement elment : e.getStackTrace()) {er.append(elment.toString()  \n);}logger.error(er.toString());System.out.println(er.toString());return null;}}3. 轨道生成及移动算法 
/** * 双轴轨道生成算法主要实现平滑加速和减速 * * param distance * return */ public static ListInteger[] getXyTrack(int distance) { boolean isPrn  false; ListInteger[] track  new ArrayListInteger[]();// 移动轨迹 try { int a  (int) (distance / 3.0)  random.nextInt(10); int h  0, current  0;// 已经移动的距离 BigDecimal midRate  new BigDecimal(0.7  (random.nextInt(10) / 100.00)).setScale(4, BigDecimal.ROUND_HALF_UP); BigDecimal mid  new BigDecimal(distance).multiply(midRate).setScale(0, BigDecimal.ROUND_HALF_UP);// 减速阈值 BigDecimal move  null;// 每次循环移动的距离 ListInteger[] subList  new ArrayListInteger[]();// 移动轨迹 boolean plus  true; Double t  0.18, v  0.00, v0; while (current  distance) { h  random.nextInt(2); if (current  distance / 2) { h  h * -1; } v0  v; v  v0  a * t; move  new BigDecimal(v0 * t  1 / 2 * a * t * t).setScale(4, BigDecimal.ROUND_HALF_UP);// 加速 if (move.intValue()  1) move  new BigDecimal(1L); if (plus) { track.add(new Integer[] { move.intValue(), h }); } else { subList.add(0, new Integer[] { move.intValue(), h }); } current  move.intValue(); if (plus  current  mid.intValue()) { plus  false; move  new BigDecimal(0L); v  0.00; } } track.addAll(subList); int bk  current - distance; if (bk  0) { for (int i  0; i  bk; i) { track.add(new Integer[] { -1, h }); } } if (isPrn) System.out.println(“getMoveTrack(”  midRate  “) a”  a  “,distance”  distance   - mid  mid.intValue()   size  track.size()); return track; } catch (Exception e) { System.out.print(e.toString()); return null; } } 4. 采用物理鼠标定位方式 
/*** 物理鼠标移动模式* * param beginX* param beginY* param distance*/public static boolean RobotMove(int beginX, int beginY, int distance) {Robot robot  null;Double curX  null, curY  null;boolean isPrn  false;try {robot  new Robot();// 从当前位置移动到滑动条位置Point location  MouseInfo.getPointerInfo().getLocation();curX  location.getX();curY  location.getY();Double xAdd  beginX - curX;Double yAdd  beginY - curY;if (isPrn)System.out.println(RobotMove() init(curX  curX  ,curY  curY  ,xAdd  xAdd  ,yAdd  yAdd  ));Double p  (xAdd.compareTo(yAdd)  0) ? Math.abs(yAdd) : Math.abs(xAdd);Double moveX  curX;Double moveY  curY;for (int k  0; k  p.intValue(); k) {moveX  xAdd / p;moveY  yAdd / p;robot.mouseMove(moveX.intValue(), moveY.intValue());robot.delay(1);}robot.mouseMove(beginX, beginY);robot.mousePress(InputEvent.BUTTON1_MASK); // 按下左键ListInteger[] track  ActionMove.getXyTrack(distance);int abX  beginX;int abY  beginY;long begin, cost;int total  track.size();Integer[] move;long sleep  0;Double singTime  (1  distance / 50.0) * 600 / distance;if (isPrn)System.out.println(move begin from(  curX  ,  curY  ) singTime  singTime);StringBuffer sb  new StringBuffer();for (int i  0; i  total; i) {begin  System.currentTimeMillis();move  track.get(i);int x  move[0];int y  move[1];abY  y;if (isPrn)System.out.println(  move(  move[0]  ));int len  Math.abs(x);for (int k  0; k  len; k) {abX  (x  0) ? 1 : -1;robot.mouseMove(abX, abY);if (k  len - 1) {cost  System.currentTimeMillis() - begin;if (len  6) {double start  singTime / (len - 1);double range  start - singTime / (len  1);sleep  new BigDecimal(start - (range / len * (k  1))).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();} else {sleep  new BigDecimal((singTime - cost) / (len - k)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();}if (sleep  0)Thread.sleep(sleep);sb.append(,[x  x  ,k  k  ,sleep  sleep  ]);}}if (isPrn  sb.length()  0)System.out.println(  |--  sb.toString());cost  System.currentTimeMillis() - begin;if (cost  singTime) {sleep  singTime.longValue() - cost;if (sleep  0)Thread.sleep(sleep);if (isPrn)System.out.println(  |-- x  x  ,end sleep  sleep);} else if (isPrn) {System.out.println(  |-- x  x  ,end cost  cost);}}robot.delay(20);return true;} catch (Throwable e) {System.out.print(RobotMove()   e.toString());return false;} finally {if (robot ! null) {robot.mouseRelease(InputEvent.BUTTON1_MASK); // 松开左键robot.mouseMove(curX.intValue(), curY.intValue());}}}四丶结语 
中国国际航空公司联合中国航空总公司和中国西南航空公司成立了中国航空集团公司,作为航空领域的翘楚依托国有资源技术实力雄厚 人才济济在吸取了同行滑动验证码的经验后自己研发了独特风格的那个验证码 从逆向代码来看 不仅借鉴了同行的技术原理还在防抓取上下了功夫 
防模拟器鼠标物理鼠标和逻辑鼠标定位不一致判断措施解决思路为让JS 这部分代码失效或这采用 物理定位鼠标的部分目前采用的是物理鼠标的方式。 从这两、点看的确让初级黑客止步但本质上 前端技术都是暴露在浏览器不管是JS 注入还是后端代理模式都会让这些小技巧无效。 很多人在短信服务刚开始建设的阶段可能不会在安全方面考虑太多理由有很多。 比如“ 需求这么赶当然是先实现功能啊 ”“ 业务量很小啦系统就这么点人用不怕的 ”  “ 我们怎么会被盯上呢不可能的 ”等等。 有一些理由虽然有道理但是该来的总是会来的。前期欠下来的债总是要还的。越早还问题就越小损失就越低。 所以大家在安全方面还是要重视。血淋淋的栗子#安全短信# 戳这里→康康你手机号在过多少网站注册过 
谷歌图形验证码在AI 面前已经形同虚设所以谷歌宣布退出验证码服务 那么当所有的图形验证码都被破解时大家又该如何做好防御呢 
相关阅读 《腾讯防水墙滑动拼图验证码》 《百度旋转图片验证码》 《网易易盾滑动拼图验证码》 《顶象区域面积点选验证码》 《顶象滑动拼图验证码》 《极验滑动拼图验证码》 《使用深度学习来破解 captcha 验证码》 《验证码终结者-基于CNNBLSTMCTC的训练部署套件》