一.背景

1.与前端对接的API接口,如果被第三方抓包并进行恶意篡改参数,可能会导致数据泄露,甚至会被篡改数据

2.与第三方公司的接口对接,第三方如果得到你的接口文档,但是接口确没安全校验,是十分不安全的

我主要围绕时间戳,token,签名三个部分来保证API接口的安全性

二.请求过程

1.用户成功登陆站点后,服务器会返回一个token,用户的任何操作都必须带了这个参数,可以将这个参数直接放到header里。

2.客户端用需要发送的参数和token生成一个签名sign,作为参数一起发送给服务端,服务端在用同样的方法生成sign进行检查是否被篡改。

3.但这依然存在问题,可能会被进行恶意无限制访问,这时我们需要引入一个时间戳参数,如果超时即是无效的。

4.服务端需要对token,签名,时间戳进行验证,只有token有效,时间戳未超时,签名有效才能被放行。

概念:

(1)开放接口

没有进行任何限制,简单粗暴的访问方式,这样的接口方式一般在开放的应用平台,查天气,查快递,只要你输入正确对应的参数调用,即可获取到自己需要的信息,我们可以任意修改参数值。

(2)Token认证获取

用户登录成功后,会获取一个ticket值,接下去任何接口的访问都需要这个参数。我们把它放置在redis内,有效期为10分钟,在ticket即将超时,无感知续命。延长使用时间,如果用户在一段时间内没进行任何操作,就需要重新登录系统。

(3)Sign签名

把所有的参数拼接一起,在加入系统秘钥,进行MD5计算生成一个sign签名,防止参数被人恶意篡改,后台按同样的方法生成秘钥,进行签名对比。

(4)重复访问

引入一个时间戳参数,保证接口仅在一分钟内有效,需要和客户端时间保持一致。

(5)拦截器

每次请求都带有这三个参数,我们都需要进行验证,只有在三个参数都满足我们的要求,才允许数据返回或被操作。

三.具体代码实现

1.编写获取tiket的接口

    /**
* 获取tiket
* @param receiveRequest
* @return
*/
@ResponseBody
@RequestMapping(value = "/gettiket",method = RequestMethod.POST)
public String gettiket(@RequestBody String data){
String result = "";
String msg = "";
try{
log.info("gettiket,入参为==="+data); JdbcTemplate jdbcTemplate = new JdbcTemplate();
String userTocken = UUID.randomUUID().toString();
//cache.put(userTocken, userMap);//数据库方式或者redis方式,这里用数据库方式
String insert_user_token_sql = "insert into user_token(pk_user_token,userid,user_token) VALUES (?,?,?)";
long pk_user_token = KeyUtils.nextId();//主键 jdbcTemplate.executeUpdate(insert_user_token_sql, new Object[]{
pk_user_token,"111",userTocken
});
result = userTocken;
msg = "{\"success\" : true,\"errorCode\" : \"200\", \"errorMsg\" : \"查询完成\", \"tiket\" :" +result + "}";
log.info("msg===="+msg);
return msg;
}catch(Exception e){
msg = "{\"success\" : true,\"errorCode\" : \"500\", \"errorMsg\" : \"查询完成\", \"data\" :" +e + "}";
return msg;
} }

2.服务端验证

主程序入口

        Map<String, String> paramMap = new HashMap<>();
String time = DateUtils.formatDate("yyyy-MM-dd HH:mm:ss.SSS");
paramMap.put("time", time);
String ticket = "056a3d29-eed3-4ee9-80aa-c03321d5302f";
paramMap.put("ticket", ticket);//userTock为我第一次请求你的单点url时传给你的userTocken
String serviceCode = "cs_demo";// 目标系统对应的密钥
String sign = null;
try {
sign = SignUtils.sing(paramMap, serviceCode, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
log.info("sign==="+sign);
CheckPerService checkPerService= new CheckPerService();
Boolean istrue = checkPerService.TicketSignAndTime( ticket, sign, time, serviceCode);
log.info("istrue==="+istrue);

工具类SignUtils

package tcc.test.utill;

import org.apache.log4j.Logger;
import org.springframework.util.DigestUtils;
import java.io.UnsupportedEncodingException;
import java.util.*; public class SignUtils {
private static final Logger a = Logger.getRootLogger(); public SignUtils() {
} public static String getContent(Map params) {
List keys = new ArrayList(params.keySet());
Collections.sort(keys);
String prestr = "";
boolean first = true; for(int i = 0; i < keys.size(); ++i) {
String key = (String)keys.get(i);
if (!"sign".equals(key) && !"_r".equals(key) && !"_result_type".equals(key) && !"_".equals(key)) {
String value = String.valueOf(params.get(key));
if (value != null && value.trim().length() != 0) {
if (first) {
prestr = prestr + key + "=" + value;
first = false;
} else {
prestr = prestr + "&" + key + "=" + value;
}
}
}
} a.info("加密字符串:" + prestr);
return prestr;
} public static String sing(Map Params, String key, String charset) throws UnsupportedEncodingException {
String signStr = null;
signStr = DigestUtils.md5DigestAsHex((getContent(Params) + key).getBytes(charset));
return signStr;
} public static void main(String[] args) throws Exception {
Map paramMap = new HashMap<String,String>();
paramMap.put("name","tcc");
paramMap.put("age","24");
String serviceCode = "siruinet";
String sing = SignUtils.sing(paramMap, serviceCode, "UTF-8");
System.out.println(sing); }
}

权限校验工具类

package tcc.test.utill;

import com.alibaba.druid.util.StringUtils;
import com.util.FieldList;
import jos.engine.core.jdbc.JdbcTemplate;
import jos.engine.des.util.DesEncryptUtils;
import org.apache.log4j.Logger; import java.util.HashMap;
import java.util.Map; /**
* Copyright (C) @2022
*
* @author: tcc
* @version: 1.0
* @date: 2022/1/31
* @time: 2:08
* @description:
*/
public class CheckPerService{
private static final Logger log = Logger.getRootLogger(); /*
接口权限校验方法1
ticket:票据
sign:签名
time:时间戳
serviceCode:服务编码*/
public static boolean TicketSignAndTime(String ticket, String sign, String time, String serviceCode){
time = time;
ticket = ticket;
sign = sign;
Map<String, String> paramMap = new HashMap<>();
paramMap.put("time", time);
paramMap.put("ticket", ticket);//ticket为第一次调用获取ticket接口的数据
serviceCode = serviceCode;// 目标系统对应的密钥
String qm = DesEncryptUtils.sing(paramMap, serviceCode, "UTF-8");
log.info("qm==="+qm);
if (!StringUtils.equals(sign, qm)) { //密钥校验错误
log.info("签名不正确");
return false;
}
log.info("签名正确");
JdbcTemplate jdbcTemplate = new JdbcTemplate();
String qr_user_token_sql = "select count(1) as count from user_token where user_token = ?";//后期改成redis
FieldList file_token = jdbcTemplate.queryField(qr_user_token_sql, new Object[]{ ticket });
int count = Integer.parseInt(file_token.get("count"));
if(count<1){
return false;
}
return true;
} /*
接口权限校验方法2
name:用户名
pwd:密码
*/
public static boolean UnmAndPwd(String name,String pwd){
JdbcTemplate jdbcTemplate = new JdbcTemplate("mzdb");
String qr_user_token_sql = "select count(1) as count from bd_user where USERNAME = ? and USERPASS = ?";//后期改成redis
FieldList file_token = jdbcTemplate.queryField(qr_user_token_sql, new Object[]{ name,pwd });
int count = Integer.parseInt(file_token.get("count"));
if(count<1){
return false;
}
return true; } }

API 接口的安全设计验证:ticket,签名,时间戳的更多相关文章

  1. API接口的安全设计验证—ticket,签名,时间戳

    概述 与前端对接的API接口,如果被第三方抓包并进行恶意篡改参数,可能会导致数据泄露,甚至会被篡改数据,我主要围绕时间戳,token,签名三个部分来保证API接口的安全性 1.用户成功登陆站点后,服务 ...

  2. HTTP API接口安全设计

    HTTP API接口安全设计 API接口调用方式 HTTP + 请求签名机制   HTTP + 参数签名机制 HTTPS + 访问令牌机制 有没有更好的方案? OAuth授权机制 OAuth2.0服务 ...

  3. API接口签名校验

    在开发app中,我们经常要为app提供接口.但是为了保证数据的安全,我们通常会对接口的参数进行加密. 1.不验证的接口api api接口请求,"http://www.xx.com/getUs ...

  4. 对飞猪H5端API接口sign签名逆向实验

    免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...

  5. SpringBoot接口 - API接口有哪些不安全的因素?如何对接口进行签名?

    在以SpringBoot开发后台API接口时,会存在哪些接口不安全的因素呢?通常如何去解决的呢?本文主要介绍API接口有不安全的因素以及常见的保证接口安全的方式,重点实践如何对接口进行签名.@pdai ...

  6. Winform混合式开发框架访问Web API接口的处理

    在我的混合式开发框架里面,集成了WebAPI的访问,这种访问方式不仅可以实现简便的数据交换,而且可以在多种平台上进行接入,如Winform程序.Web网站.移动端APP等多种接入方式,Web API的 ...

  7. 开放api接口签名验证

    不要急,源代码分享在最底部,先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候, ...

  8. 总结的一些微信API接口

    本文给大家介绍的是个人总结的一些微信API接口,包括微信支付.微信红包.微信卡券.微信小店等,十分的全面,有需要的小伙伴可以参考下. 1. [代码]index.php <?php include ...

  9. api接口签名验证(MD5)

    不要急,源代码分享在最底部,先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候, ...

随机推荐

  1. Linux 安装并启用 PHP-FPM

    首先,在编译时带上 --enable-fpm 参数: [root@localhost local]# yum -y install libxml2 libxml2-devel gd gd-devel ...

  2. [ vue ] 解耦vuex(按照组件来组织vuex的结构)

    问题描述 随着应用复杂度的增加,vuex用一个 store/index.js 文件来描述已经很难维护了,我们想把这些状态分割到单独文件里面. 参考1:https://vuex.vuejs.org/zh ...

  3. Echart可视化学习(六)

    文档的源代码地址,需要的下载就可以了(访问密码:7567) https://url56.ctfile.com/f/34653256-527823386-04154f 柱状图定制 官网找到类似实例, 适 ...

  4. httprunner3.x全网最详细教程

    一.所需环境 wiindows10以上 python3.6以上 httprunner3.1.6(最新版本) pycharm社区版 二.安装httprunner 1.卸载旧版本 卸载之前版本的命令为:p ...

  5. SQLServer触发器调用JavaWeb接口

    这几天接到一个需求需要吧不同系统的数据库进行同步,需要我做一个中间平台进行连接,瞬间就想到了触发器调用接口然后通过API进行传递再写入另一个数据库. sqlServer触发器调用JavaWeb接口 1 ...

  6. Qt中编译器

    很多时候,Qt构建项目编译的过程中会报错,大部分报错是因为qt的设置出现问题,很多时候环境配置时要选择合适的编译器,debugger调试器等,这里对一些名词解释,内容对新手很友好,大佬就不用看啦. M ...

  7. 虚拟化技术kvm,xen,vmware比较

    目前市面上常用的虚拟机技术主要有KVM.xen.vmware. KVM是指基于Linux内核(Kernel-based)的虚拟机(Virtual Machine).KVM最大的好处就在于它是与Linu ...

  8. 列表页面(html+css+js)

    html文件 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...

  9. K8s QoS Pod资源服务质量控制

    Kubernetes 中如果一个 Node 节点上的 Pod 占用资源过多并且不断飙升导致 Node 节点资源不足,可能会导致为了保证节点可用,将容器被杀掉.在遇见这种情况时候,我们希望先杀掉那些不太 ...

  10. Core 3.1 MVC 抛异常“InvalidOperationException: No service for type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory' has been registered.”

    .NET Core 的版本是 3.1遇到的问题是 Action 中 return View() 的时候报错 An unhandled exception occurred while processi ...