银联卡8583协议小额免密免签交易总结

news2024/11/25 4:36:22

之前做过金融支付这块儿。到过北京石景山区银行卡检测中心过检PBOC的level2认证,去过上海银联总部和湖南银联对接银联卡和扫码支付。对金融支付和卡交易这块儿熟悉。现在这块儿知识用不上了总结下留作备忘,同时分享给有需要的人。

关于免密免密交易

免密支付指的是在支付一定金额时,不用输入密码,即可完成交易。小额免密免签,也叫小额双免。是中国银联提供的一种小额快速支付服务。银联闪付就是免密支付的应用,通过联机方式,使用具有“闪付”标识的银行银联芯信用卡,或承载个人信用卡信息的移动支付产品,将银联芯片卡靠近终端“闪付”感应区即可完成支付。

这是大概在2015年10月银联为了紧跟时代潮流和方便用户推出的新业务。我们知道原来的银行卡用起来很不方便,随后它推出的有一个"电子现金"功能,但还是需要先到ATM机上往卡里圈存一部分钱才能用,这部分圈存到卡片上的钱俗称电子现金,消费通过带有闪付标识的银联pos机使用,只需挥卡不用输入密码和签名即可消费,用在一些小额支付场景如公交,地铁和商超。

现在这种小额支付免密交易很流行,各大平台和支付结构都有一定小额的免密交易。银联小额免密免签不需要密码也能保障资金安全,因为小额免密免签使用高安全性的金融ic卡,同时银联联合银行为持卡人提供风险控制和赔付机制。

银联8583协议

8583协议在金融系统中很常用,报文简短,定义清晰规范。是基于ISO8583报文国际标准的包格式的通讯协议,8583包最多由128个字段域组成,每个域都有统一的规定,并有定长与变长之分。8583包前面一段为位图,它是打包解包确定字段域的关键代替。

曾写过一个java版的8583解析协议,全互联网最简单好用的,地址在这里:

java版银联8583协议解析,超简单超直观的实现及示例(全互联网最简单)_特立独行的猫a的博客-CSDN博客_银联8583demo

这里写图片描述

 

这里写图片描述

银联公网接入规范

银联提供了公网https接入规范。HTTP交易报文由http头加传统交易报文数据组成。http头中主要定义了交易报文类型及长度,同时需符合http协议规范。

POST /mjc/webtrans/XX HTTP/1.1
HOST: 145.4.206.XX:XX
User-Agent: XXXX
Cache-Control: no-cache
Content-Type:x-ISO-TPDU/x-auth
Accept: */*
Content-Length: length

https握手流程

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL。在发送HTTP报文之前需要建立SSL连接,以此加密HTTP数据。关系如下图所示:

SSL连接分为两个阶段,即握手和数据传输阶段;传输任何应用数据之前必须先完成握手。

握手协议:

  1. 对服务器进行认证;
  2. 确立用于保护数据传输的加密密钥;
  3. 记录协议:
  4. 传输数据;

银联通信MAC算法

8583通信有个MAC校验,相关算法参照博主博文:

ANSI-X99MAC算法和PBOC的3DES MAC算法_特立独行的猫a的博客-CSDN博客

Java的HTTP接口封装

没有使用第三方的jar包,使用java自带的net.HttpURLConnection包的封装,简单易用。支持http和https,可以让https不验证本地证书。

package com.yang.utils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * https请求工具类
 *
 * @author yang
 * @date 2018/6/6 19:12
 */
public class HttpsUtils {

    /*
     * https请求是在http请求的基础上加上一个ssl层
     */
    public static String doPost(String requestUrl, String bodyStr, Map<String, String> header, String charset, String contentType) throws Exception {
        System.out.printf("https post 请求地址:%s 内容:%s", requestUrl, bodyStr);
        charset = null == charset ? "utf-8" : charset;

        // 创建SSLContext
        SSLContext sslContext = SSLContext.getInstance("SSL");
        TrustManager[] trustManagers = {new X509TrustManager() {
            /*
             * 实例化一个信任连接管理器
             * 空实现是所有的连接都能访问
             */
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }};
        // 初始化
        sslContext.init(null, trustManagers, new SecureRandom());
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        URL url = new URL(requestUrl);
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
        httpsURLConnection.setSSLSocketFactory(sslSocketFactory);

        // 以下参照http请求
        httpsURLConnection.setDoOutput(true);
        httpsURLConnection.setDoInput(true);
        httpsURLConnection.setUseCaches(false);
        httpsURLConnection.setRequestMethod("POST");
        httpsURLConnection.setRequestProperty("Accept-Charset", charset);
        if (null != bodyStr) {
            httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(bodyStr.length()));
        }
        if (contentType == null) {
            httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        } else {
            httpsURLConnection.setRequestProperty("Content-Type", contentType);
        }
        if (!header.isEmpty()) {
            for (Map.Entry<String, String> entry : header.entrySet()) {
                httpsURLConnection.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }
        httpsURLConnection.connect();

        // 读写内容
        OutputStream outputStream = null;
        InputStream inputStream = null;
        InputStreamReader streamReader = null;
        BufferedReader bufferedReader = null;
        StringBuffer stringBuffer;
        try {
            if (null != bodyStr) {
                outputStream = httpsURLConnection.getOutputStream();
                outputStream.write(bodyStr.getBytes(charset));
                outputStream.close();
            }

            if (httpsURLConnection.getResponseCode() >= 300) {
                throw new Exception("https post failed, response code " + httpsURLConnection.getResponseCode());
            }

            inputStream = httpsURLConnection.getInputStream();
            streamReader = new InputStreamReader(inputStream, charset);
            bufferedReader = new BufferedReader(streamReader);
            stringBuffer = new StringBuffer();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            if (streamReader != null) {
                streamReader.close();
            }
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        }
        System.out.printf("--- https post 返回内容:%s", stringBuffer.toString());
        return stringBuffer.toString();
    }

    public static byte[] doUpHttpsPost(String requestUrl, byte[] bodyHex) throws Exception {
        System.out.printf("请求地址:%s\n", requestUrl);
        // 创建SSLContext
        SSLContext sslContext = SSLContext.getInstance("SSL");
        TrustManager[] trustManagers = {new X509TrustManager() {
            /*
             * 实例化一个信任连接管理器
             * 空实现是所有的连接都能访问
             */
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                //return new X509Certificate[0];
                return new X509Certificate[]{};
            }
        }};
       
        // 初始化
        sslContext.init(null, trustManagers, new SecureRandom());
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        URL url = new URL(requestUrl);
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
        httpsURLConnection.setSSLSocketFactory(sslSocketFactory);
        HostnameVerifier hv =  new HostnameVerifier(){
            @Override
            public boolean verify(String string, SSLSession ssls) {
                return true;//To change body of generated methods, choose Tools | Templates.
            }
        };
        httpsURLConnection.setHostnameVerifier(hv);

        // 以下参照http请求
        httpsURLConnection.setDoOutput(true);
        httpsURLConnection.setDoInput(true);
        httpsURLConnection.setUseCaches(false);
        httpsURLConnection.setRequestMethod("POST");
        
        String strLen = String.valueOf(bodyHex.length);
       
        httpsURLConnection.setRequestProperty("User-Agent", "Donjin Http 0.1");
        httpsURLConnection.setRequestProperty("Content-Length", strLen);
        httpsURLConnection.setRequestProperty("Accept", "*/*");
        httpsURLConnection.setRequestProperty("Content-Type", "x-ISO-TPDU/x-auth");
        httpsURLConnection.setRequestProperty("Cache-Control", "no-cache");
        httpsURLConnection.connect();

        // 读写内容
        OutputStream outputStream = null;
        InputStream inputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
          
            outputStream = httpsURLConnection.getOutputStream();
            outputStream.write(bodyHex);
            outputStream.flush();
            outputStream.close();
            System.out.printf("\n--- https ResponseCode:%d\n", httpsURLConnection.getResponseCode());
            if (httpsURLConnection.getResponseCode() >= 300) {
                throw new Exception("https post failed, response code " + httpsURLConnection.getResponseCode());
            }

            inputStream = httpsURLConnection.getInputStream();
            byteArrayOutputStream = new ByteArrayOutputStream();
            int len = 0;
            byte[] bytes = new byte[inputStream.available()];
            while ((len = inputStream.read(bytes)) != -1) {
                byteArrayOutputStream.write(bytes, 0, len);
            }//写入数据
            return byteArrayOutputStream.toByteArray();
             //byte[] nbytes = bytes.c
        } catch (Exception e) {
            throw e;
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            if (byteArrayOutputStream != null) {
                byteArrayOutputStream.close();
            }
        }
    }

}

免密免签交易流程

测试源码在这里:

https://download.csdn.net/download/qq8864/87280073

报文示例

test...
2022/12/13 18:57:16 Server:XXX.XX.XX.XXX
2022/12/13 18:57:16 Port:0
2022/12/13 18:57:16 Url:https://202.xx.25.xx:xx/mjc/webtrans/ABC
pack 8583 fields
Print fields...

==========================================
Len:    0057
Tpdu:   6002100000
Head:   613100311108
Msge:   0800
Bitmap: 0020000000c00016

==========================================
[field:11] [000001]

------------------------------
[field:41] [3134313030303033]

------------------------------
[field:42] [313431343230313431313130303033]

------------------------------
[field:60] [len:0011] [000000000030]

------------------------------
[field:62] [len:0025] [53657175656e6365204e6f3132333036303134313030303033]

------------------------------
[field:63] [len:0003] [303031]

------------------------------
2022/12/13 18:57:16 connect:server=https://2xx.101.25.18x:2x141/mjc/webtrans/ABC
send:0057600210000061310031110808000020000000c0001600000131343130303030333134313432303134313131303030330011000000000030002553657175656e6365204e6f31323330363031343130303030330003303031
ReadFile err: open UP.pem: no such file or directory
2022/12/13 18:57:16 begin post...
User-Agent : Donjin Http 0.1
Content-Type :  x-ISO-TPDU/x-auth
Cache-Control : no-cache
2022/12/13 18:57:16 recv ok!len=123
recv:007960000002106131003111080810003800010ac00014000001185716121308000952103138353731363035373232373030313431303030303331343134323031343131313030303300110000001700300040b31544e6cf8a5d091450ad5970c2143e7e960636afd9761ce25f41f70000000000000000c7e1867b
ans 8583 fields
解析成功
Print fields...

==========================================
Len:    0079
Tpdu:   6002100000
Head:   613100311108
Msge:   0810
Bitmap: 003800010ac00014

==========================================
[field:11] [000001]

------------------------------
[field:12] [185716]

------------------------------
[field:13] [1213]

------------------------------
[field:32] [len:08] [00095210]

------------------------------
[field:37] [313835373136303537323237]

------------------------------
[field:39] [3030]

------------------------------
[field:41] [3134313030303033]

------------------------------
[field:42] [313431343230313431313130303033]

------------------------------
[field:60] [len:0011] [000000170030]

------------------------------
[field:62] [len:0040] [b31544e6cf8a5d091450ad5970c2143e7e960636afd9761ce25f41f70000000000000000c7e1867b]

------------------------------
mackey:e5986862d3efefae
2022/12/13 18:57:16 签到成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/89355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生 | Kubernetes 实战】12、K8s 四层代理 Service 入门到企业实战应用(下)

目录 一、创建 Service&#xff1a;type 类型是 NodePort 1.1 创建一个 pod 资源 1.2 创建 service&#xff0c;代理 pod 在集群外访问 service&#xff1a; 数据转发流程&#xff1a; 二、创建 Service&#xff1a;type 类型是 ExternalName 2.1 创建 pod 2.2 创建…

相关数据库

h2 需要用以下 初始化一下 第一次启动需要加入下面代码 h2 创建表 可以直接用jdbc 然后进行测试 不需要链接mysql redis 想要启动redis 现在 该目录下 输入俩个cmd 一个cmd 输入redis-cli 到启动太 输入 shutdown 然后再另一个cmd 输入 redis-server.exe redis.windows.con…

如何利用电商模式,灵活结合当地产品生态全力助农,实现乡村振兴

随着互联网时代的发展&#xff0c;人们的消费观念和消费习惯逐渐被改变&#xff0c;绿色环保观念深入人心&#xff0c;人们加大了对农产品的高要求和高需求&#xff0c;同时&#xff0c;近年来国家对农业的重视和政策支持&#xff0c;促进了农产品电商的蓬勃发展&#xff0c;已…

YOLOV7学习记录之原理+代码介绍

博主计划做一个目标检测跟踪项目&#xff0c;考虑使用YOLO系列模型来作为目标检测器&#xff0c;如今YOLO项目已经更新到了YOLOV7版本&#xff0c;因此便来学习一下相关原理&#xff0c;完成相关实验工作。 论文链接&#xff1a;https://arxiv.org/abs/2207.02696 网络结构 YO…

【字节码】Java Instrumentation 简介 以及 ASM 组合案例

1.概述 本文来自:深入理解JVM字节码 并且对其进行补充。 2.Java Instrumentation简介 JDK从1.5版本开始引人了java.lang.instrument 包,开发者可以更方便的实现字节码增强。其核心功能由java.lang.instrument.Instrumentation 提供,这个接口的方法提供了注册类文件转换器…

python列表添加元素append(),extend(),insert(),+list的区别及说明

这篇文章主要介绍了python列表添加元素append(),extend(), insert(),list的区别及说明&#xff0c;具有很好的参考价值&#xff0c;希望对大家有所帮助。 列表添加元素append(),extend(),insert(),list区别 回忆初学python的时候&#xff0c;对列表list添加元素时&#xff0c…

[附源码]Nodejs计算机毕业设计基于web技术的米其林轮胎管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

C# 程序的组织

一 程序的组织 ① 名字控件 程序的逻辑组织&#xff1b; ② 嵌套类型 类中嵌套类型&#xff1b; ③ 程序集 程序的物理组织&#xff1b; 二 名字空间 1 名字控件的概念 逻辑划分&#xff1b;避免名字冲突&#xff1b; 2 名字空间的声明 namespace xxx.xxxxx{} 可嵌套 3 …

Jmeter 性能测试之阶梯式场景、波浪式场景

推荐阅读&#xff1a; [内部资源] 想拿年薪30W的软件测试人员&#xff0c;这份资料必须领取~ Python自动化测试全栈性能测试全栈&#xff0c;挑战年薪40W 1 阶梯式场景&#xff08;负载测试&#xff09; 该场景主要应用在负载测试里面&#xff0c;通过设定一定的并发线程数…

云游戏拉开产业化大幕

配图来自Canva可画 在过去十多年间&#xff0c;音乐和视频已经完成了线下存储到线上串流的变迁&#xff0c;VCD、CD、MP3也早已成为有历史记忆的收藏品&#xff0c;然而游戏业的“革命”——云游戏行业才刚刚开始。 尤其是随着5G和边缘计算的发展&#xff0c;更高的带宽、更低…

cubeIDE开发, 定时器TIM与外部中断NVIC实践案例

一、定时器功能 1.1 定时器分类 STM32 的定时器分为高级定时器、 通用定时器 、基本定时器三种。 这三个定时器成上下级的关系&#xff0c;即基本定时器有的功能通用定时器都有&#xff0c;而且还增加了向下、向上/向下计数器、PWM生成、输出比较、输入捕获等功能&#xff1b;而…

高并发编程之多线程锁和CallableFuture 接口

5 多线程锁 5.1 锁的八个问题演示 package com.xingchen.sync;import java.util.concurrent.TimeUnit;class Phone {public static synchronized void sendSMS() throws Exception {//停留4秒TimeUnit.SECONDS.sleep(4);System.out.println("------sendSMS");}publ…

AXI协议规范超详细中文总结版

link AXI协议规范中文翻译版 来源&#xff1a;https://github.com/lizhirui/AXI_spec_chinese 综述 本文参考分析整理总结了AMBA AXI and ACE Protocol Specification文档的AXI总线协议规范部分&#xff0c;错误之处欢迎指出。 AMBA AXI协议支持高性能高频的系统设计&#xff0…

【视觉高级篇】25 # 如何用法线贴图模拟真实物体表面

说明 【跟月影学可视化】学习笔记。 什么是法线贴图&#xff1f; 法线贴图就是在原物体的凹凸表面的每个点上均作法线&#xff0c;通过RGB颜色通道来标记法线的方向&#xff0c;你可以把它理解成与原凹凸表面平行的另一个不同的表面&#xff0c;但实际上它又只是一个光滑的平…

巧用 Chrome:网络知多少

开发者如数家珍的工具中&#xff0c;Chrome 想必是众多人心目中的白月光&#xff0c;倒也不是它有多么优秀&#xff0c;而是多亏同行浏览器们的衬托。其开源的内核 Chromium 也成就众多养家糊口的岗位&#xff0c;比如 Edge、Opera、QQ 浏览器、360 浏览器等等国内外一票浏览器…

物联网开发笔记(62)- 使用Micropython开发ESP32开发板之控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程:环境搭建

一、目的 这一节我们学习如何使用我们的ESP32开发板来控制ILI9341 3.2寸TFT-LCD触摸屏进行LVGL图形化编程的第一步&#xff1a;环境搭建。 关键字&#xff1a;3.2寸SPI串口TFT液晶显示屏模块 ILI9341驱动 LCD触摸屏 240*320 LVGL图形化编程 XPT2046触摸屏芯片IC 二、环境 ESP…

实机安装CentOS7.9操作系统图文(保姆级)教程

一、制作启动U盘 1、下载Ventoy软件 去Ventoy官网下载Ventoy软件&#xff08;Download . Ventoy&#xff09;如下图界面 ​ 2、制作启动盘 选择合适的版本以及平台下载好之后&#xff0c;进行解压&#xff0c;解压出来之后进入文件夹&#xff0c;如下图左边所示&#xff0c…

Hive 之数据透视表

文章目录什么是数据透视表&#xff1f;创建数据源基于各产品在各个平台半年内的月销售额与汇总&#xff0c;制作数据透视表什么是数据透视表&#xff1f; 数据透视表是一种工具&#xff0c;用于帮助用户理解和分析大量数据。它通常是一个二维表格&#xff0c;可以让用户以不同…

java计算机毕业设计springboot+vue航空公司电子售票系统-机票预订系统

项目介绍 通篇文章的撰写基础是实际的应用需要,然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程,以远程教育系统的实际应用需要出发,架构系统来改善现远程教育系统工作流程繁琐等问题。不仅如此以操作者的角度来说,该系统的架构能够对多媒体课程进…

手把手教你使用SpringBoot做一个员工管理系统【代码篇·下】

手把手教你使用SpringBoot做一个员工管理系统【代码篇下】1.增加员工实现2.修改员工信息3.删除员工4.404页面配置5.注销1.增加员工实现 新增添加员工的按钮&#xff1a; <h2><a class"btn btn-sm btn-success" th:href"{/addemp}">添加员工&…