API 接口的安全设计验证:ticket,签名,时间戳
一.背景
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,签名,时间戳的更多相关文章
- API接口的安全设计验证—ticket,签名,时间戳
概述 与前端对接的API接口,如果被第三方抓包并进行恶意篡改参数,可能会导致数据泄露,甚至会被篡改数据,我主要围绕时间戳,token,签名三个部分来保证API接口的安全性 1.用户成功登陆站点后,服务 ...
- HTTP API接口安全设计
HTTP API接口安全设计 API接口调用方式 HTTP + 请求签名机制 HTTP + 参数签名机制 HTTPS + 访问令牌机制 有没有更好的方案? OAuth授权机制 OAuth2.0服务 ...
- API接口签名校验
在开发app中,我们经常要为app提供接口.但是为了保证数据的安全,我们通常会对接口的参数进行加密. 1.不验证的接口api api接口请求,"http://www.xx.com/getUs ...
- 对飞猪H5端API接口sign签名逆向实验
免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...
- SpringBoot接口 - API接口有哪些不安全的因素?如何对接口进行签名?
在以SpringBoot开发后台API接口时,会存在哪些接口不安全的因素呢?通常如何去解决的呢?本文主要介绍API接口有不安全的因素以及常见的保证接口安全的方式,重点实践如何对接口进行签名.@pdai ...
- Winform混合式开发框架访问Web API接口的处理
在我的混合式开发框架里面,集成了WebAPI的访问,这种访问方式不仅可以实现简便的数据交换,而且可以在多种平台上进行接入,如Winform程序.Web网站.移动端APP等多种接入方式,Web API的 ...
- 开放api接口签名验证
不要急,源代码分享在最底部,先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候, ...
- 总结的一些微信API接口
本文给大家介绍的是个人总结的一些微信API接口,包括微信支付.微信红包.微信卡券.微信小店等,十分的全面,有需要的小伙伴可以参考下. 1. [代码]index.php <?php include ...
- api接口签名验证(MD5)
不要急,源代码分享在最底部,先问大家一个问题,你在写开放的API接口时是如何保证数据的安全性的?先来看看有哪些安全性问题在开放的api接口中,我们通过http Post或者Get方式请求服务器的时候, ...
随机推荐
- CSS基础 行内元素/行内块元素设置垂直对齐方式及常见使用案例
vertical-align 属性值 效果 baseline 基线对齐 top 顶部对齐 middle 中心对齐 bottom 底部对齐 使用案例1:百度搜索框左边和右边底部没有对齐 使用vertic ...
- 解决VirtualBox 运行时报内存不能written
在VirtualBox 虚拟机中安装系统的时候,突然报"0x00000000指令,该内存不能written",只能强制停止,这个问题要怎么解决呢? 解决办法是恢复系统主题3个dll ...
- Python_使用smtplib+email完成邮件发送
本文以第三方QQ邮箱服务器演示如何使用python的smtplib+email完成邮箱发送功能 一.设置开启SMTP服务并获取授权码 开启QQ邮箱SMTP服务 开启的最后一步是发送短信验证,获取 au ...
- python的赋值、浅拷贝和深拷贝
""" 一.赋值在python中就是简单的对象引用 """ list_a = ["aaa", "bbb&quo ...
- CentOS7中安装pip的方法
1.安装epel-release [root@localhost ~]# yum -y install epel-release 2.安装python-pip [root@localhost ~]# ...
- 微信小程序css继承
在微信小程序里写的全局样式,pages里的组件是可以继承的,但是components里只能继承font和color属性.
- 彻彻底底地理解TCP三次握手和四次挥手的全部过程
三次握手 我们先提出一些问题,但是我们暂且不回答这些问题,下面我会尽我所能详尽地讲解TCP的三次握手过程,然后看完你可以在评论区留下你对问题的答案,我们可以一起探讨. 为什么要握手 为什么是三次而不是 ...
- 收到西门子发来的UG告知函怎么办?Solidworks盗版被查如何防范?厂商是怎么样查到公司在用盗版,有什么方法可以核实真假?……
收到西门子发来的UG告知函怎么办?Solidworks盗版被查如何防范?厂商是怎么样查到公司在用盗版,有什么方法可以核实真假?--很多企业信息化管理leader或者老板都希望能够通过一些取巧的办法来防 ...
- Java中运算符及其优先级、自动类型提升、类型转化
自动类型提升的规则 两个操作数中有一个为double型的数据,计算结果提升为double. 两个操作数中无double型,有一个float,计算结果自动提升为float. ...
- 5.14-HTTP间通信
1.社长社员通信WEBSOCKET WebSocket 是一种标准协议,用于在客户端和服务端之间进行双向数据传输.但它跟 HTTP 没什么关系,它是一种基于 TCP 的一种独立实现. 以前客户端想知道 ...