为了能在靠不住的系统里比较可靠地进行一些重要操作,人们用了很多办法,其中一个叫“双因子验证”。例如,美军为了防止误发射导弹,采用这样的策略:如果要发射导弹,则不仅需要两个操作员各自用确认钥匙开一把锁才能验证发射代码的正确性,还需要两人把两把发射钥匙插进两个发射孔同时转动,而两个孔还设计得距离遥远以防一个人同时转两把钥匙,这就是它的高级版本。

比如你要用电脑进行网银转账。设计网银安全体系的人就要假设你的账号密码早晚会被坏人窃取。在这种情况下怎么防止坏人用你的账号密码登录你的网银呢?

大家比较熟悉的“U盾”就是一种解决办法。这个设备是独立于电脑而存在的。要在电脑上操作网银,把你账户里的钱转给别人,就需要把这个设备连在电脑上。坏人没有你的“U盾”,所以即使拿到了你的账户密码,也动不了你的钱。在这里,你的密码是一个验证因子,U盾是另一个验证因子。需要密码+U盾才能验证身份登录网银转账,这就是双因子验证。

U盾这种解决办法是相对比较安全的。但网络安全领域有这么一个“不可能三角“:“安全-方便-廉价“这三者无法同时达成。手机相对于电脑,是一个独立设备。短信验证码相对于用户口令,也是独立的。如果我们假设攻击者即使掌握了很多用户个人数据,能入侵用户电脑,也仍无法获取手机短信,那么用手机短信作为一个独立验证因子也是可靠的。

下面看一下如何实现短信验证码功能,打开网建短信通网址:当然,有很多服务提供商可以实现这一功能,这里笔者只是为了举例。

Java验证码校验处理_Java验证码校验处理

注册并登录后,可以找到自己的秘钥。

Java验证码校验处理_apache_02

用户可以得到5条免费的试用短信。 下面给出示例:

<!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
<dependency>
    <groupId>commons-httpclient</groupId>
	<artifactId>commons-httpclient</artifactId>
	<version>3.1</version>
</dependency>
package com.clawer.wzfbi;

import java.io.IOException;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;

/**
 * 短信发送
 */
public class App {
	public static void main(String[] args) {

		HttpClient client = new HttpClient();
		// 准备
		PostMethod post = new PostMethod("http://sms.webchinese.cn/web_api/");
		post.addRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=gbk");// 在头文件中设置转码
		// 设置发送的内容
		NameValuePair[] data = { new NameValuePair("Uid", "callmejack"), // 注册的用户名
				new NameValuePair("Key", "d41d8cd98151333204e980"), // 注册成功后,登录网站使用的密钥
				new NameValuePair("smsMob", "13*********"), // 您要发送验证码的手机号码
				new NameValuePair("smsText", "您的验证码为:555512") };// 设置短信内容
		post.setRequestBody(data);

		try {
			client.executeMethod(post);

			// 处理返回结果
			Header[] headers = post.getResponseHeaders();
			int statusCode = post.getStatusCode();
			System.out.println("statusCode:" + statusCode); // statusCode=200表示请示成功!
			for (Header h : headers) {
				System.out.println(h.toString());
			}
			String result = new String(post.getResponseBodyAsString().getBytes("gbk")); // 设置编码格式
			System.out.println(result);
			post.releaseConnection();
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

主要有一点需要注意:需要在用户信息修改里面填入相应的机构名称,以避免被运营商当做是垃圾短信过滤掉。

Java验证码校验处理_网银_03