【java】java接口安全之接口签名

这篇具有很好参考价值的文章主要介绍了【java】java接口安全之接口签名。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.自定义的加签规则

1.采用Http协议的get或post方式提交
其中get请求参数放在Params中,post请求参数放在Params中,或者body中传递
2.增加接口请求时间戳参数:timestamp ,放到 Params,参与签名计算
如:timestamp=1665727846  ,(秒)

3.签名算法说明
1)获取params参数和body中的非空、非空串的参数
2)所有的参数按参数名升序排序
3)按参数名及参数值互相连接组成一个请求参数串(paramStr),格式如下:
		name1=value1&name2=value2 ...
4)将secretKey(服务器密钥:4f6cxxxx38d892xxx),拼接到请求参数串的尾部,得到签名字符串(signStr)
		paramStr+"&key="+secretKey
5)将signStr通过MD5加密,得到 签名(sign) 

4. timestamp 、sign 放到 Params中,与其他接口请求参数一起发送给服务端

2.自定义的接口签名解签工具类

package com.camojojo.common.core.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.camojojo.common.core.constant.WebError;
import com.camojojo.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Flux;

import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 接口签名验证
 * @author:yuchen
 * @createTime:2022/10/13 19:50
 */
@Slf4j
public class SignUtil {

    private static final String secretKey = "key=xxxxxxxxx";
    private static final String SIGN = "sign";
    private static final String TIMESTAMP = "timestamp";


    public static void checkSign(ServerHttpRequest request,long expireTime) {
        log.info("签名验证");
        String timeStr = request.getQueryParams().getFirst(TIMESTAMP);
        String sign =  request.getQueryParams().getFirst(SIGN);
        log.info("sign={},timeStr={}",sign,timeStr);
        if(StrUtil.isBlank(timeStr) || StrUtil.isBlank(sign)){
            throw new ServiceException(WebError.ERROR_COMMON_PARAMETER_IS_EMPTY,"参数为空");
        }
        long requestTime = Long.valueOf(timeStr);
        long now = System.currentTimeMillis()/1000;
        log.info("now={}",now);
        // 请求发起时间与当前时间超过expireTime,则接口请求过期
        if(now - requestTime > expireTime){
            throw new ServiceException(WebError.ERROR_API_REQUEST_EXPIRE,"接口请求过期");
        }
        Map<String, String> paramMap = new HashMap<>();
        String body = resolveBodyFromRequest(request);
        log.info("获取body中的参数={}",body);
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        queryParams.forEach((k, v) -> {
            if(v != null && StrUtil.isNotBlank(v.get(0)) && !k.equalsIgnoreCase(SIGN)){
                paramMap.put(k,v.get(0));
            }
        });
        log.info("获取params中的参数={}",paramMap);
        if(StrUtil.isNotBlank(body)){
            JSONObject jsonObject = JSON.parseObject(body);
            for(String key :jsonObject.keySet()){
                if(StrUtil.isNotBlank(jsonObject.getString(key))){
                    paramMap.put(key,jsonObject.getString(key));
                }
            }
        }
        String serverSign = getSign(paramMap);
        log.info("serverSign={}",serverSign);
        if(!serverSign.equals(sign)){
            throw new ServiceException(WebError.ERROR_API_SIGN,"接口签名错误");
        }
    }

    public static String getSign(Map<String, String> map) {
        //按Key进行排序
        Map<String, String> sortMap = sortMapByKey(map);
        StringBuilder signStr= new StringBuilder();
        if(sortMap != null){
            for (Map.Entry<String, String> entry : sortMap.entrySet()) {
                signStr.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }
        String sign = signStr.append(secretKey).toString();
        log.info("signStr={}",signStr);
        return SecureUtil.md5(sign);
    }

    /**
     * 使用 Map按key进行排序
     * @param map
     * @return
     */
    public static Map<String, String> sortMapByKey(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        //升序排序
        Map<String, String> sortMap = new TreeMap<>(String::compareTo);
        sortMap.putAll(map);
        return sortMap;
    }


    private static String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        // 获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }

}

3.进一步优化

        在实际实现中,发现body中参数可能包含数组,或者对象数组,此时按照以上需求也需要对每个key进行排序,否则会由于顺序原因造成前后端生成的签名不一致。

        后续优化,将body转成流,再进行md5加密,生成签名。这样就避免了对body处理繁琐的加签操作。文章来源地址https://www.toymoban.com/news/detail-552079.html

到了这里,关于【java】java接口安全之接口签名的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java安全——数字签名

    数字签名 签名类 签名的jar文件可以通过Java的 jarsigner 工具进行管理。 jarsigner 工具使用密钥库中的信息来查找特定的实体,并使用这些信息对jar文件进行签名或验证签名。 要创建签名的jar文件,我们可以使用以下命令: 这个命令会使用密钥库中的信息对xyz.jar文件进行签名。

    2024年02月12日
    浏览(35)
  • 【全栈接口测试进阶系列教程】postman接口测试实战cookie,token,session鉴权,Base64,MD5,RSA加密,Sign签名,持续集成postman+Newman+jenkins

    目录 【一:postman简介和安装以及postman的登录和注册】 一、postman下载 二、安装、注册/登陆 三、简单使用 1.postman模拟发送get请求: 2.postman模拟发送post请求:  3.post数据类型说明: 【二:postman发送get请求,post请求实战以及页签详解】 发送GET请求 响应页面 发送POST请求 【三

    2024年02月10日
    浏览(33)
  • 前端和Java验签以太坊钱包签名实现中心化登录

    相信做过一些dapp项目的小伙伴都知道,当dapp需要和中心化的业务系统交互时,怎么验证登录成了一个问题。要dapp输入登录账户密码就很奇怪,违背了设计初衷,不登录吧,中心化系统又没有安全可言。 故此需要一个特定的动作。只有当钱包持有人授权登录(连接钱包),前

    2024年04月23日
    浏览(21)
  • CSDN博客接口基于java调用的x-ca-signature签名算法研究

    本人业余时间会写写CSDN的博客,查看下博客数据,展现量、阅读量什么的。在“作品数据-单篇文章分析”菜单中可以看到每篇文章的总体展现量、阅读量,要是想看每篇文章每日的访问量需要再次点击列表后边的“查看详情”显示的曲线图,一个一个点击着实有些麻烦,所

    2024年02月10日
    浏览(31)
  • 【Java可执行命令】(十)JAR文件签名工具 jarsigner:通过数字签名及验证保证代码信任与安全,深入解析 Java的 jarsigner命令~

    jarsigner 是Java Development Kit (JDK) 提供的一个命令行工具,用于对JAR文件进行数字签名 。它的设计目的是提供身份验证和完整性保护,确保在分发和发布Java应用程序时的安全性。 数字签名是一种用于确认数据的来源和完整性的机制。使用私钥对数据进行签名,并使用公钥进行验

    2024年02月13日
    浏览(34)
  • Java应用服务系统安全性,签名和验签浅析

    随着互联网的普及,分布式服务部署越来越流行,服务之间通信的安全性也是越来越值得关注。这里,笔者把应用与服务之间通信时,进行的的安全性相关, 加签 与 验签 ,进行了一个简单的记录。 网关服务接口,暴漏在公网,被非法调用? 增加了token安全验证,被抓包等

    2024年02月13日
    浏览(31)
  • 【Java基础】了解Java安全体系JCA,使用BouncyCastle的ED25519算法生成密钥对、数据签名

    总共分为4个部分: JCA( Java Cryptography Architecture, Java加密体系结构) :提供了基本的加密框架,包括证书、数字签名、消息摘要和密钥对产生器等。它允许开发者通过Java API来访问和操作加密相关的功能。 JCE( Java Cryptography Extension, Java加密扩展包) :JCE在JCA的基础上作了

    2024年04月25日
    浏览(27)
  • 从加密到签名:如何使用Java实现高效、安全的RSA加解密算法?

    目录 1. 接下来让小编给您们编写实现代码!请躺好 ☺ 1.1 配置application.yml文件 1.2 RSA算法签名工具类 1.3  RSA算法生成签名以及效验签名测试 1.4 RSA算法生成公钥私钥、加密、解密工具类 1.5 RSA算法加解密测试 我们为什么要使用RSA算法来进行加解密?  RSA 加密算法是一种非对

    2024年02月12日
    浏览(42)
  • WEB攻防-Java安全&JWT攻防&Swagger自动化&算法&签名&密匙&Druid未授权

    知识点: 1、Java安全-Druid监控-未授权访问信息泄漏 2、Java安全-Swagger接口-文档导入联动批量测试 2、Java安全-JWT令牌攻防-空算法未签名密匙提取 参考:https://developer.aliyun.com/article/1260382 Druid是阿里巴巴数据库事业部出品,为监控而生的数据库连接池。Druid提供的监控功能,监

    2024年02月04日
    浏览(33)
  • 小程序绕过 sign 签名

    之前看到了一篇文章【小程序绕过sign签名思路】之前在做小程序渗透时也遇到了这种情况,但是直接放弃测试了,发现这种思路后,又遇到了这种情况,记录下过程。 并没有漏洞分享,仅仅是把小程序也分享出来,方便大家测试学习。 小程序 父母邦亲子旅行酒店营地乐园活

    2024年03月20日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包