网站建设入门书网站开发的推荐

当前位置: 首页 > news >正文

网站建设入门书,网站开发的推荐,淘宝网站怎么做的好,刚刚刚刚刚刚刚刚刚刚刚刚刚刚刚文章目录一、使用背景二、实现方案三、具体流程四、优化五、代码实现六、后续优化一、使用背景 过去对于接口的验证我一般都是直接在登录时为用户发放token#xff0c;用户在随后的操作中携带了token则允许请求。 但是这样的验证方式存在有一定的问题#xff0c;如果token被… 文章目录一、使用背景二、实现方案三、具体流程四、优化五、代码实现六、后续优化一、使用背景 过去对于接口的验证我一般都是直接在登录时为用户发放token用户在随后的操作中携带了token则允许请求。 但是这样的验证方式存在有一定的问题如果token被泄露被他人获取那么就会有非法请求的风险。其他人可以使用这个token自行调用接口进行请求传入非法参数甚至进行注入攻击等可能会造成严重的问题。 即存在以下安全问题 请求身份是否合法请求参数是否被篡改 为了防止这种情况的发生我们验证接收到的数据与客户端发送的数据一致且让接口只能被客户端请求。 二、实现方案 既然要实现接口只能被客户端请求那么我们不难想到可以与客户端达成某些约定让客户端按一定的规则发送请求。 只需要服务端与客户端约定一套密钥客户端在发送请求时拼接上私钥后使用单向加密算法进行加密服务端收到后使用相同的私钥和加密算法进行加密后验证是否与前端客户端传递的值相同。 这样的方案可以使得用户即使拿到了token没有私钥的话加密后的数据与服务端加密后的肯定不相同而无法通过验证。篡改参数同样会产生相同的问题从而保证了接口的安全性。 三、具体流程 按照请求参数名的字母升序排列非空请求参数包含accesskey使用URL键值对的格式即key1value1key2value2…拼接成字符串A在字符串A最后拼接上secretkey得到字符串B对B进行MD5运算并将得到的字符串所有字符转换为大写得到sign值携带参数accesskey和sign进行请求 四、优化 以上方式虽然解决了非法用户请求和请求参数被篡改的问题但是还存在着重复使用请求参数伪造二次请求的隐患。 为了解决这个问题我们不难想到请求时生成一个唯一的标识符那么服务端在接收到请求之后只需要验证是否已经接受过改请求的标识即可。 不过以上方式还存在一个问题就是服务端要保存那么多的请求标识并不现实所以我们可以设置一个过期时间过期了就将标识删除。并让请求的时候携带一个时间戳超过时间的请求直接打回。 五、代码实现 假设请求接口test?param1helloparam2world 那么前端需要发送请求test?accesskeyxxxparam1helloparam2worldnonce随机唯一标识timestamp当前时间戳signxxx sign MD5(“accesskeyxxxnonce随机唯一标识param1helloparam2worldsecretkeyxxxtimestamp当前时间戳”).toUpperCase() 注意请求接口中的参数可以不按顺序而用于生成sign的字符串中的各个参数必须按照一定的顺序与后端约定 后端验签 Component public class ApiVerifyUtil {public static final String SECRET_KEY secretkey;public static final String ACCESS_KEY accesskey;public static final String TIMESTAMP_KEY timestamp;public static final String NONCE_KEY nonce;public static final String SIGN_KEY sign;private static final HashMapString, String KEY_PAIR;static {KEY_PAIR new HashMap();KEY_PAIR.put(app1, password1); // 为客户端分配的密钥KEY_PAIR.put(app2, password2);}Autowiredprivate RedisTemplateString, String redisTemplateBean;private static RedisTemplateString, String redisTemplate;PostConstructpublic void init() {redisTemplate redisTemplateBean;}public static final Integer OK 0;public static final Integer PARAMS_ERROR 1;public static final Integer LACK_ACCESSKEY 2;public static final Integer ACCESSKEY_INVALID 3;public static final Integer LACK_NONCE 4;public static final Integer LACK_TIMESTAMP 5;public static final Integer LACK_SIGN 6;public static final Integer REQUEST_TIMEOUT 7;public static final Integer REQUEST_REPEATED 8;public static final Integer REQUEST_INVALID 9;// 超时时间(ms)public static final long TIMEOUT 1000 * 60 * 15;public static final String AND ;public static final String EQUALS ;public static Integer verify(HashMapString, String params) {if (params null || params.isEmpty()) {return PARAMS_ERROR;}// accessKey为空或不合法(即不存在对应的密钥)或请求参数不全则直接打回String accessKey, secretKey, timestamp, nonce, sign;if ((accessKey params.get(ACCESS_KEY)) null) {return LACK_ACCESSKEY;}if ((secretKey KEY_PAIR.get(accessKey)) null) {return ACCESSKEY_INVALID;}if ((timestamp params.get(TIMESTAMP_KEY)) null) {return LACK_TIMESTAMP;} else if (Long.parseLong(timestamp) - System.currentTimeMillis() TIMEOUT) {// 超过15分钟return REQUEST_TIMEOUT;}if ((nonce params.get(NONCE_KEY)) null) {return LACK_NONCE;} else {SetString nonceSet redisTemplate.opsForSet().members(nonce);if (nonceSet ! null nonceSet.contains(nonce)) {return REQUEST_REPEATED;}}if ((sign params.get(SIGN_KEY)) null) {return LACK_SIGN;}params.remove(SIGN_KEY);// 加密需要拼接上密钥params.put(SECRET_KEY, secretKey);ArrayListString keyList new ArrayList(params.keySet());// 按顺序构造Collections.sort(keyList);StringBuilder sb new StringBuilder();for (String key : keyList) {sb.append(key).append().append(params.get(key)).append();}String newSign sb.toString();newSign MD5.create().digestHex16(newSign.substring(0, newSign.length() - 1).toUpperCase());if (newSign.equals(sign)) {redisTemplate.opsForSet().add(nonce, nonce);return OK;}return REQUEST_INVALID;}public static HashMapString, String getParams(HttpServletRequest httpServletRequest) {String queryString httpServletRequest.getQueryString();String[] split queryString.split(AND);HashMapString, String params new HashMap();for (String param : split) {params.put(param.split(EQUALS)[0], param.split(EQUALS)[1]);}return params;}public static HashMapString, String getParams(String queryString) {String[] split queryString.split(AND);HashMapString, String params new HashMap();for (String param : split) {params.put(param.split(EQUALS)[0], param.split(EQUALS)[1]);}return params;}}六、后续优化 加入接口被调用的阈值限制对接口访问频率设置一定阈值对超过阈值的请求进行屏蔽及预警。白名单机制指定一些可以访问我们暴露接口的域名不在白名单里面的域名发过来的请求直接拒绝。