系统安全认证设计实现

4 篇文章 1 订阅

1.Token生成逻辑

                生成时间戳timestamp和时间戳nonce(保证每次唯一).

                signOriginStr=  v_name + timestamp + nonce; //待签名字符串

                salt=func(); //例如:通过一些特定算法,计算出新的salt,例如进行128个字节,散列后 组合在散列,在加上timestamp

                token = HMAC(signOriginStr, salt);//最后签名

2.具体实现(加密时字段顺序不能变):

                salt="HSH_APP_SIGN"

                nonce为随机字符串,保证不重复,建议生成算法:nonce=MD5(UUID.randomUUID() + uuid)或直接用 UUID.randomUUID()

                signOriginStr=  v_name + timestamp(毫秒) + nonce

          TOKEN= MD5(signOriginStr + SHA(SHA(salt + timestamp) + timestamp));

3.接口认证规则

               a.生成Token的参数全都不为空

               b.取参数使用同样的加密规则与参数Token一致

               c.判断时间戳是否在60s之内,如果不在抛弃记录错误。

               d:判断nonce是否已经存在,如果存在则抛弃记录错误。(每一个nonce直接放入redis设置60s的过期时间,1秒1000个请求, redis只需要存储60万个keys)

 

4.nonce生成

function nonce() {
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";
 
    var nonce = s.join("");
    return nonce;
}

 

5.uuid生成

[[[UIDevice currentDevice] identifierForVendor] UUIDString]; (iOS)

 

android:

public static String getUniqueID(Context context) {
    long id = ((long) getDeviceImei(context).hashCode() << 32) | getMac(context).hashCode();
 String m_szLongID = getPesudoUniqueID() + id;
 // compute md5
 MessageDigest m = null;
 try {
        m = MessageDigest.getInstance("MD5");
 } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
 }
    m.update(m_szLongID.getBytes(), 0, m_szLongID.length());
 // get md5 bytes
 byte p_md5Data[] = m.digest();
 // create a hex string
 String m_szUniqueID = new String();
 for (int i = 0; i < p_md5Data.length; i++) {
        int b = (0xFF & p_md5Data[i]);
 // if it is a single digit, make sure it have 0 in front (proper padding)
 if (b <= 0xF)
            m_szUniqueID += "0";
 // add number to string
 m_szUniqueID += Integer.toHexString(b);
 }   // hex string to uppercase
 m_szUniqueID = m_szUniqueID.toUpperCase();
 return m_szUniqueID;
}

6.示例:

long timestamp = 1555324734L;
String nonce = "324734";
String v_name = "3.2.1.0";
String mac = "48-5A-B6-CE-57-91";

加密后:

sha1 = 39d05da6ab1d9364a047515b6f0212237770069d
sha2 = 84c5e99c2d520469bbd254edb53247739b528bef
TOKEN = f916281ccd0d93fa909658b030be50a6

 

7.Java实现

代码设计基于springboot自动装配策略:

       SecurePolicy.java 接口安全校验的核心类

package com.common.secure;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;

import com.common.utils.EncryptUtil;

/**
 * 接口安全Token校验策略
 * 
 * @author dwj
 * @Date 2019年4月17日
 * @version 1.0
 * @Description TOKEN= MD5(signOriginStr + SHA(SHA(salt + timestamp) +
 *              timestamp));
 */
public class SecurePolicy {
	private static Logger LOGGER = LoggerFactory.getLogger(SecurePolicy.class);

	private long tokenActiveTime;// token有效时间
	private String salt;

	private RedisTemplate<String, String> redisTemplate;

	public SecurePolicy(SecurePolicyProperties config,
			RedisTemplate<String, String> redisTemplate) {
		this.tokenActiveTime = config.getTokenActiveTime();
		this.salt = config.getSalt();
		this.redisTemplate = redisTemplate;
	}

	/**
	 * 接口安全校验
	 * 
	 * @param verifyToken
	 *            待校验Token
	 * @param signOriginStr
	 *            签名原始字符串
	 * @param nonce
	 * @param timestamp
	 * @return
	 */
	public boolean verify(String verifyToken, String signOriginStr,
			String nonce, long timestamp) {
		if (timestampTimeout(timestamp) && nonceRetry(nonce)
				&& tokenVerity(verifyToken, signOriginStr, timestamp)) {
			return true;
		}
		return false;
	}

	// 时间戳过期
	private boolean timestampTimeout(long timestamp) {
		long now = System.currentTimeMillis();
		// 时间戳过期
		if (Math.abs(now - timestamp) > tokenActiveTime) {
			LOGGER.warn("异常请求,时间戳过期!");
			return false;
		}
		return true;
	}

	// nonce是否被重放
	private boolean nonceRetry(String nonce) {
		// nonce是否被重放
		if (!redisTemplate.opsForValue().setIfAbsent(nonce.toString(),
				String.valueOf(System.currentTimeMillis()))) {
			LOGGER.warn("异常请求,NONCE重放!");
			return false;
		}
		// 120s过期
		redisTemplate.expire(nonce.toString(), tokenActiveTime,
				TimeUnit.MILLISECONDS);
		return true;
	}

	/**
	 * TOKEN校验
	 * 
	 * @param verifyToken
	 * @param signOriginStr
	 * @param timestamp
	 * @return
	 */
	private boolean tokenVerity(String verifyToken, String signOriginStr,
			long timestamp) {
		// token校验
		String token = EncryptUtil.signEncrypt(signOriginStr, salt, timestamp);
		if (!verifyToken.equals(token)) {
			LOGGER.warn("异常请求,TOKEN不一致!");
			return false;
		}
		return true;
	}
}

       SecurePolicyAutoConfiguration.java 自动装配类

package com.common.secure;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 自动配置
 * 
 * @author dwj
 * @Date 2019年6月24日
 * @version 1.0
 */
@Configuration
@EnableConfigurationProperties({ SecurePolicyProperties.class })
public class SecurePolicyAutoConfiguration {

	@Bean
	public SecurePolicy securePolicyInit(
			SecurePolicyProperties securePolicyProperties,
			RedisTemplate<String, String> redisTemplate) {
		return new SecurePolicy(securePolicyProperties, redisTemplate);
	}
}

       SecurePolicyProperties.java 配置类

package com.common.secure;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 安全策略配置
 * 
 * @author dwj
 * @Date 2019年6月24日
 * @version 1.0
 */
@ConfigurationProperties(prefix = "secure.policy")
public class SecurePolicyProperties {
	private long tokenActiveTime = 2 * 60 * 1000;
	private String salt = "HSH_APP_SIGN";

	public SecurePolicyProperties() {

	}

	public SecurePolicyProperties(long tokenActiveTime, String salt) {
		this.tokenActiveTime = tokenActiveTime;
		this.salt = salt;
	}

	public long getTokenActiveTime() {
		return tokenActiveTime;
	}

	public void setTokenActiveTime(long tokenActiveTime) {
		this.tokenActiveTime = tokenActiveTime;
	}

	public String getSalt() {
		return salt;
	}

	public void setSalt(String salt) {
		this.salt = salt;
	}

}

使用方法:

1.通过springboot扫描secure初始化核心类实例,

2.new SecurePolicy()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值