概述

在企业级应用开发中,不可缺失的一个微服务/模块就是登陆校验。常规的有:用户名/密码验证,加强版的有:密码加盐混淆验证外。考虑到密码泄露类事件的时有发生,以及因为计算机技术发展产生的黑客暴力枚举破解的算力加持。故而,需要在用户名/密码校验基础上,增加更高级的校验,一般来说有三类:图片验证码,手机短信,邮箱验证码;其中图片验证码又有滑动图片验证码。

常规密码

如数字密码,4位数字,实际上可穷举,10000种可能性暴力破解。

安全意识较强的网站,此时一般会设置允许错误的次数,如3/5次错误即触发账户锁定1小时或者5小时不定,防止密码被暴力破解的隐患。

图片验证码

原理就是生成一张指定尺寸规格的图片,在图片里面有4位或者多位数字,为了应对发展日益成熟的人工智能图片识别技术,加入混淆元素,一定程度上可以防止机器识别。

CAPTCHA,Completely Automated Public Turing test to tell Computers and Humans Apart,全自动区分计算机和人类的图灵测试,是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。

可以自研,不过推荐使用开源技术,如谷歌验证码工具kaptcha。

Kaptcha

Kaptcha 是一个可高度配置的实用验证码生成工具,可自由配置的选项:

  • 验证码字体及其大小、颜色
  • 验证码内容的范围(数字,字母,中文汉字)
  • 验证码图片的大小,边框,边框粗细,边框颜色
  • 验证码的干扰线
  • 验证码的样式(鱼眼样式、3D、普通模糊、…)

​Kaptcha官网​​​​GitHub​

maven依赖:

<dependency>
<groupId>com.google.code.kaptcha</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3</version>
</dependency>

google官方提供的 pom 无法正常使用,使用阿里云仓库对应 kaptcha:

<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>

配置类:com.google.code.kaptcha.util.Config,自带默认值,支持配置修改

  1. kaptcha.border:图片边框,合法值:yes , no
  2. kaptcha.border.color:边框颜色,合法值: r,g,b (and optional alpha) 或white,black,blue
  3. kaptcha.border.thickness:边框厚度
  4. kaptcha.producer.impl:图片实现类
  5. kaptcha.textproducer.impl:文本实现类
  6. kaptcha.textproducer.char.string:文本集合,验证码值从此集合中获取
  7. kaptcha.textproducer.char.length:验证码长度
  8. kaptcha.textproducer.font.names:字体
  9. kaptcha.textproducer.font.size:字体大小
  10. kaptcha.textproducer.font.color:字体颜色,合法值: r,g,b 或white,black,blue.
  11. kaptcha.textproducer.char.space:文字间隔
  12. kaptcha.noise.impl:干扰实现类
  13. kaptcha.noise.color:干扰颜色,合法值: r,g,b或white,black,blue.
  14. kaptcha.obscurificator.impl:图片样式:水纹​​com.google.code.kaptcha.impl.WaterRipple​​​,鱼眼​​com.google.code.kaptcha.impl.FishEyeGimpy​​​,阴影​​com.google.code.kaptcha.impl.ShadowGimpy​
  15. kaptcha.word.impl:文字渲染器
  16. kaptcha.background.impl:背景实现类
  17. kaptcha.background.clear.from:背景颜色渐变,开始颜色
  18. kaptcha.background.clear.to:背景颜色渐变, 结束颜色
  19. kaptcha.image.width:图片宽
  20. kaptcha.image.height:图片高
  21. kaptcha.session.key:session键
  22. kaptcha.session.date:session时间

使用方式:

  1. Java Config
@Component
public class KaptchaConfig {
@Bean
public DefaultKaptcha getDDefaultKaptcha() {
DefaultKaptcha dk = new DefaultKaptcha();
Properties properties = new Properties();
// 图片边框
properties.setProperty("kaptcha.border", "yes");
Config config = new Config(properties);
dk.setConfig(config);

return dk;
}
}
  1. ​kaptchaConfig.xml​​文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
<property name="config">
<bean class="com.google.code.kaptcha.util.Config">
<constructor-arg type="java.util.Properties">
<props>
<!--是否使用边框-->
<prop key="kaptcha.border">yes</prop>
</props>
</constructor-arg>
</bean>
</property>
</bean>
</beans>

然后引入配置类​​@ImportResource(locations={"classpath:kaptchaConfig.xml"})​

定义Controller:

/**
* 验证码工具
*/
@Autowired
private DefaultKaptcha defaultKaptcha;

@RequestMapping("/validate")
public void defaultKaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
byte[] captcha;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
// 将生成的验证码保存在session中或Redis
String createText = defaultKaptcha.createText();
request.getSession().setAttribute("rightCode", createText);
BufferedImage bi = defaultKaptcha.createImage(createText);
ImageIO.write(bi, "jpg", out);
} catch (Exception e) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
captcha = out.toByteArray();
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream sout = response.getOutputStream();
sout.write(captcha);
sout.flush();
sout.close();
}

/**
* 校对验证码
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView imgvrifyControllerDefaultKaptcha(HttpServletRequest request, HttpServletResponse response) {
ModelAndView model = new ModelAndView();
String rightCode = (String) request.getSession().getAttribute("rightCode");
String tryCode = request.getParameter("tryCode");
if (!rightCode.equals(tryCode)) {
model.addObject("info", "验证码错误,请再输一次!");
model.setViewName("login");
} else {
model.addObject("info", "登陆成功");
model.setViewName("index");
}
return model;
}

easy-captcha

另外你可能会看到一个easy-captcha项目,和google kaptcha没有半毛钱关系。看到easy,哈哈,你没猜错,确实是国人"开源"的项目。文档还算丰富。
​​​EasyCaptcha-GitHub​

<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>

使用:

// deviceId是前端生成的随机字符串,用于验证码存储于Redis时生成key
@GetMapping("/code/{deviceId}")
public void createCode(@PathVariable String deviceId, HttpServletResponse response) throws Exception {
Assert.notNull(deviceId, "机器码不能为空");
// 设置请求头为输出图片类型
CaptchaUtil.setHeader(response);
// 三个参数分别为宽、高、位数
Captcha captcha = new SpecCaptcha(100, 35, 4);
// 设置类型:字母数字混合
captcha.setCharType(Captcha.TYPE_DEFAULT);
// 保存验证码,存储于Redis
validateCodeService.saveImageCode(deviceId, captcha.text().toLowerCase());
// 输出图片流
captcha.out(response.getOutputStream());
}

滑动图片验证码

逻辑:根据鼠标滑动轨迹,坐标位置,拖动速度等来判断是否人为操作。

核心流程:

  1. 后端随机生成抠图和带有抠图阴影的背景图片,后台保存随机抠图位置坐标
  2. 前端实现滑动交互,将抠图拼在抠图阴影之上,获取到用户滑动距离值

邮件

安全性比图片验证码高,

短信

安全性比图片验证码高,

​https://github.com/fightingape/sailing​

腾讯云短信服务
需要注册腾讯云开通短信服务:
​​​ https://cloud.tencent.com/product/isms/getting-started​​​ 开通短信服务成功后,获取 SDKAppID 和 AppKey,云短信应用 SDKAppID 和 AppKey 可在 短信控制台 的应用信息里获取。
申请签名并确认审核通过 一个完整的短信由短信签名和短信正文内容两部分组成,短信签名需申请和审核,签名可在 短信控制台的相应服务模块【内容配置】中进行申请,详细申请操作请参见 创建签名。发送国际短信时,允许不携带签名。
申请模板并确认审核通过 短信或语音正文内容模板需申请和审核,模板可在 短信控制台 的相应服务模块【内容配置】中进行申请,详细申请操作请参见 创建正文模板。

手势校验

手势密码,实际上是从1~9选出若干个数字形成密码,且数字可以相连,弱化版的数字密码。手势密码设置的规则:密码不小于4个点,点在第一次经过时不允许被跳过
直接抛结论,各个数字的个数的可能性:

  • 4位1624个
  • 5位7152个
  • 6位26016个
  • 7位72912个
  • 8位140704个
  • 9位和8位相同

双因素认证

Two-Factor Authentication,2FA,最早得知于GitHub网站。

从密码学理论上说,用于身份认证主要有三方面要素:

  1. 需要用户记忆的身份认证内容,如密码或×××号码等
  2. 用户拥有认证硬件,如USB Key,智能卡(IC卡),磁卡等
  3. 用户本身拥有的唯一特征,如指纹、瞳孔、声音等。

单独来看,每个要素独立存在时,都有其脆弱性。而把两种要素结合起来,实现双重要素认证,可以有效提高系统访问控制的安全性,就是双因素认证。双因素认证是一种适合企业的访问控制策略,它将访问控制过程中个人身份识别更客观化,有效地防止来自外部的身份欺诈和来自内部的更隐蔽的网络侵犯。一般的企业都有标识身份的员工IC卡,可以利用这张卡来实现双因素认证。基于过多增加企业信息化成本的角度出发,以下方案采用的是员工卡IC卡+用户密码来进行安全访问控制。

指纹校验

每个人的指纹都不一样,满足唯一性。

缺点:

  1. 如亲属之间指纹存在相似性, 算法的精度不高容易导致识别错误;
  2. 在接触东西时遗留的指纹信息容易被他人引用,安全性不高。

人脸校验

目前的人脸识别与经验系统,大多数情况下只是作为一个活体检测,