【威锋网-注册安全分析报告-无验证方式导致安全隐患】

前言

由于网站注册入口容易被黑客攻击,存在如下安全问题:

1. 暴力破解密码,造成用户信息泄露

2. 短信盗刷的安全问题,影响业务及导致用户投诉

3. 带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞

在这里插入图片描述

所以大部分网站及App 都采取图形验证码或滑动验证码等交互解决方案, 但在机器学习能力提高的当下,连百度这样的大厂都遭受攻击导致点名批评, 图形验证及交互验证方式的安全性到底如何? 请看具体分析

一、 威锋网PC 注册入口

简介: 威锋网自建立之日起一直是人气中文iPhone社区,给广大iPhone爱好者提供了一个自由交流,探讨,学习的平台,为iPhone在中国的应用及普及发挥了领军作用。

在这里插入图片描述

二、 安全性分析报告:

前端界面分析,威锋网未采取任何验证措施,存在验证的安全隐患,同行一般会在注册下发短信验证码时采用图形验证、行为验证方式。

在这里插入图片描述

三、 测试方法:

1 模拟器交互部分

private final String INDEX_URL = "https://www.feng.com/";

	@Override
	public RetEntity send(WebDriver driver, String areaCode, String phone) {
		try {
			RetEntity retEntity = new RetEntity();
			driver.get(INDEX_URL);
			Thread.sleep(1000);
			driver.findElement(By.xpath("//a[text()='注册']")).click();

			WebElement nameElemet = driver.findElement(By.xpath("//input[@placeholder='请输入用户名']"));
			nameElemet.sendKeys("top_" + phone);
			// 输入手机号
			WebElement phoneElemet = driver.findElement(By.xpath("//input[@placeholder='请输入手机号']"));
			phoneElemet.sendKeys(phone);

			// 点击发送验证码按钮
			WebElement sendElemet = driver.findElement(By.xpath("//div/span[text()='获取验证码']"));
			if (sendElemet != null)
				sendElemet.click();
			Thread.sleep(1);
			WebElement exitsElement = ChromeDriverManager.waitElement(driver, By.className("ivu-message-notice-content-text"), 15);
			String exitsInfo = (exitsElement != null) ? exitsElement.getText() : null;
			if (exitsInfo != null) {
				System.out.println("phone=" + phone + ",exitsInfo=" + exitsInfo);
				retEntity.setMsg(exitsInfo);
				retEntity.setRet(0);
				return retEntity;
			}
			Thread.sleep(1000);

			WebElement gtElemet = ChromeDriverManager.waitElement(driver, By.xpath("//div/span[@class='count']"), 5);
			String 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 测试结果输出,测试中发现,如果手机号已注册,会直接提示该手机号已注册

在这里插入图片描述

  由于碰到严重设计缺陷,本次测评非常简单

附早期的代码,采用的行为验证:


@Override
	public RetEntity reg(CloseableHttpClient httpclient, CookieStore cookieStore, Hashtable<String, String> input, String phone) {
		RetEntity retEntity = new RetEntity();
		System.setProperty("webdriver.chrome.driver", OCRUtil.chromePath + File.separator + "chromedriver.exe");
		WebDriver driver = new ChromeDriver();
		try {
			driver.get(INDEX_URL);
			// 输入手机 号 密码 确认密码
			WebElement inputPhoneElemet = driver.findElement(By.xpath("//input[@name='phone_number']"));
			inputPhoneElemet.sendKeys(phone);
			// 获取验证码点击按钮[a id=validation_code]
			By getCodeBtn = By.cssSelector("#validation_code");
			WebElement getCodeElemet = driver.findElement(getCodeBtn);
			getCodeElemet.click();
			sleep(2000);
			// 点球点
			By moveBtn = By.cssSelector(".feng_captcha_block_piece.feng_captcha_slider_piece");
			WebElement moveElemet = driver.findElement(moveBtn);
			// 移动距离点(左门柱)
			int[][] distance = getMoveDistance(driver, WeiFeng.class.getSimpleName(), phone);
			// 移动
			move(driver, moveElemet, distance);
			retEntity.setRet(0);
			return retEntity;
		} catch (Exception e) {
			logger.error(e.toString());
			retEntity.setRet(-1);
			return retEntity;
		} finally {
			driver.quit();
			delImg(WeiFeng.class.getSimpleName(), phone);// 删除图片
		}
	}
/**
	 * 移动 三次
	 * 
	 * @param driver
	 * @param element
	 * @param distance
	 * @throws InterruptedException
	 */
	private static void move(WebDriver driver, WebElement element, int[][] distance) throws InterruptedException {
		Actions actions = new Actions(driver);
		for (int i = 2; i >= 0; i--) {
			actions.clickAndHold(element).perform();// 按住鼠标左键不释放
			int moveX = (distance[0][0] + 68 * i - 270) / 2;
			int moveY = distance[1][0] + 34 * 2 - 500;
			Thread.sleep(500 + new Random().nextInt(700));
			actions.moveByOffset(moveX, moveY).perform();// 移动
			Thread.sleep(300 + new Random().nextInt(300));
			actions.release(element).perform();// 释放鼠标左键
		}
	}

	/**
	 * 计算需要平移的距离
	 * 
	 * @param driver
	 * @return
	 * @throws IOException
	 */
	public static int[][] getMoveDistance(WebDriver driver, String spCode, String phone) throws IOException {
		String imgPrefix = spCode + phone;
		String pageSource = driver.getPageSource();
		String fullImageUrl = getFullImageUrl(pageSource);
		FileUtils.copyURLToFile(new URL(fullImageUrl), new File(basePath + "result/" + imgPrefix + FULL_IMAGE_NAME + ".jpg"));
		initMoveArray(driver);
		// 把两张图片剪切后拼接还原
		restoreImage(imgPrefix + FULL_IMAGE_NAME);
		BufferedImage fullBI = ImageIO.read(new File(basePath + "result/" + imgPrefix + FULL_IMAGE_NAME + "result3.jpg"));
		for (int j = fullBI.getHeight() / 2; j > fullBI.getHeight() / 3; j--) {
			for (int i = 0; i < fullBI.getWidth(); i++) {
				int[] fullRgb = new int[3];
				fullRgb[0] = (fullBI.getRGB(i, j) & 0xff0000) >> 16;
				fullRgb[1] = (fullBI.getRGB(i, j) & 0xff00) >> 8;
				fullRgb[2] = (fullBI.getRGB(i, j) & 0xff);

				if ((fullRgb[0] >= 38 && fullRgb[0] <= 77) && (fullRgb[1] >= 38 && fullRgb[1] <= 77) && (fullRgb[2] >= 38 && fullRgb[2] <= 77)) {
					int[][] pos = new int[2][1];
					pos[0][0] = i;
					pos[1][0] = j;
					return pos;
				}
			}
		}
		throw new RuntimeException("未找到需要平移的位置");
	}

	/**
	 * 获取move数组
	 * 
	 * @param driver
	 */
	private static void initMoveArray(WebDriver driver) {
		Document document = Jsoup.parse(driver.getPageSource());
		Elements elements = document.select("[class=feng_captcha_image_wrap]").first().children();
		int i = 0;
		for (Element element : elements) {
			Pattern pattern = Pattern.compile(".*background:.*&quot;\\)(.*?)px (.*?)px.*");
			Matcher matcher = pattern.matcher(element.toString());
			if (matcher.find()) {
				String width = matcher.group(1);
				String height = matcher.group(2);
				moveArray[i][0] = Integer.parseInt(width.trim());
				moveArray[i++][1] = Integer.parseInt(height.trim());
			} else {
				throw new RuntimeException("解析异常");
			}
		}
	}

	/**
	 * 还原图片
	 * 
	 * @param type
	 */
	private static void restoreImage(String type) throws IOException {
		// 把图片裁剪为2 * 10for (int i = 0; i < 20; i++) {
			ImageIOHelper.cutPic(basePath + "result/" + type + ".jpg", basePath + "result/" + type + i + ".jpg", -moveArray[i][0], -moveArray[i][1], 54, 250);
		}
		// 拼接图片
		String[] b = new String[10];
		for (int i = 0; i < 10; i++) {
			b[i] = String.format(basePath + "result/" + type + "%d.jpg", i);
		}
		ImageIOHelper.mergeImage(b, 1, basePath + "result/" + type + "result1.jpg");
		// 拼接图片
		String[] c = new String[10];
		for (int i = 0; i < 10; i++) {
			c[i] = String.format(basePath + "result/" + type + "%d.jpg", i + 10);
		}
		ImageIOHelper.mergeImage(c, 1, basePath + "result/" + type + "result2.jpg");
		ImageIOHelper.mergeImage(new String[] { basePath + "result/" + type + "result1.jpg", basePath + "result/" + type + "result2.jpg" }, 2, basePath + "result/" + type + "result3.jpg");
		// 删除产生的中间图片
		for (int i = 0; i < 20; i++) {
			new File(basePath + "result/" + type + i + ".jpg").delete();
		}
		new File(basePath + "result/" + type + "result1.jpg").delete();
		new File(basePath + "result/" + type + "result2.jpg").delete();
	}

	public void delImg(String spCode, String phone) {
		File dirFile = new File(basePath + "result/");

		if (!dirFile.exists()) {
			logger.debug("文件目录不存在:" + basePath + "result/");
			return;
		}
		File[] files = dirFile.listFiles();
		String prefix = spCode + phone;
		for (File file : files) {
			if (file.getName().startsWith(prefix)) {
				file.delete();
			}
		}
	}

	/**
	 * 从后台源码中获取原始图,然后转换成URL返回
	 * 
	 * @param pageSource
	 * @return
	 */
	private static String getFullImageUrl(String pageSource) {
		String url = null;
		String divStr = null;
		Document document = Jsoup.parse(pageSource);
		Elements select = document.select("[class=feng_captcha_image_wrap]");
		String style = select.html();
		if (style != null) {
			divStr = style.substring(0, style.indexOf("</div>"));
		}
		if (divStr != null) {
			int beginIndex = divStr.indexOf("&quot;") + 6;
			int endIndex = divStr.lastIndexOf("&quot;");
			url = divStr.substring(beginIndex, endIndex);
		}
		return url;
	}

二丶结语

威锋网作为IPHONE 在国内知名的媒体公司, 具有很高的人气和影响力,之前测试时记得好像是采用网易易盾的验证方式,在最近测试不知道为何去掉了, 是因为没钱了还是对安全的不重视,总之,测试结果就是随便你怎么攻击都可以,这也有点太开发了, 短信验证码难道不要钱吗 ? 这对黑客来说肯定是好消息, 弄个简单的脚本就可以搞定

很多人在短信服务刚开始建设的阶段,可能不会在安全方面考虑太多,理由有很多。
比如:“ 需求这么赶,当然是先实现功能啊 ”,“ 业务量很小啦,系统就这么点人用,不怕的 ” , “ 我们怎么会被盯上呢,不可能的 ”等等。

有一些理由虽然有道理,但是该来的总是会来的。前期欠下来的债,总是要还的。越早还,问题就越小,损失就越低。

所以大家在安全方面还是要重视。(血淋淋的栗子!)#安全短信#

戳这里→康康你手机号在过多少网站注册过!!!

谷歌图形验证码在AI 面前已经形同虚设,所以谷歌宣布退出验证码服务, 那么当所有的图形验证码都被破解时,大家又该如何做好防御呢?

>>相关阅读
《腾讯防水墙滑动拼图验证码》
《百度旋转图片验证码》
《网易易盾滑动拼图验证码》
《顶象区域面积点选验证码》
《顶象滑动拼图验证码》
《极验滑动拼图验证码》
《使用深度学习来破解 captcha 验证码》
《验证码终结者-基于CNN+BLSTM+CTC的训练部署套件》

  • 17
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值