首页 > 其他分享 >揭密支付安全:为什么你的交易无法被篡改

揭密支付安全:为什么你的交易无法被篡改

时间:2024-01-01 19:31:55浏览次数:37  
标签:揭密 RSA 验签 算法 密钥 支付 篡改 签名

这是《百图解码支付系统设计与实现》专栏系列文章中的第(4)篇。也是支付安全系列的第(1)篇。

本文主要讲清楚支付系统中为什么要做签名验签,哪些是安全的算法,哪些是不安全的算法,以及对应的核心代码实现。

专栏地址:百图解码支付系统设计与实现


通过这篇文章,你可以了解到:

  1. 什么是签名验签
  2. 支付系统为什么一定要做签名验签
  3. 哪些是安全的算法,哪些是不安全的算法
  4. 常见签名验签算法核心代码
  5. 联调中常见的问题


1. 什么是签名验签

在电子支付的万亿市场中,安全无疑是核心中的核心。有一种称之为“签名验签”的技术在支付安全领域发挥着至关重要的作用。那什么是签名验签呢?

签名验签是数字加密领域的两个基本概念。

签名:发送者将数据通过特定算法和密钥转换成一串唯一的密文串,也称之为数字签名,和报文信息一起发给接收方。

验签:接收者根据接收的数据、数字签名进行验证,确认数据的完整性,以证明数据未被篡改,且确实来自声称的发送方。如果验签成功,就可以确信数据是完好且合法的。


假设被签名的数据(m),签名串(Σ),散列函数(H),私钥(Pr),公钥(Pu),加密算法(S),解密算法(S^),判断相等(eq)。

简化后的数学公式如下:

签名:Σ=S[H(m), Pr]。

验签:f(v)=[H(m) eq S^(Σ, Pu)]。


流程如下:

揭密支付安全:为什么你的交易无法被篡改_验签

签名流程

  1. 散列消息:对消息(m)应用散列函数(H)生成散列值(h)。
  2. 加密散列值:使用发送方的私钥 ( Pr ) 对散列值 ( h ) 进行加密,生成签名 ( Σ )。 Σ = S(h, Pr)

把数字签名(Σ)和原始消息(m)一起发给接收方。


验签流程

  1. 散列收到的消息:使用同样的散列函数 ( H ) 对消息 ( m ) 生成散列值 ( h' )。 h' = H(m)
  2. 解密签名:使用发送方的公钥 ( Pu ) 对签名 (Σ ) 进行解密,得到散列值 ( h )。 h = S^(Σ, Pu)
  3. 比较散列值:比较解密得到的散列值 ( h ) 与直接对消息 ( m ) 散列得到的 ( h' ) 是否一致。 验证成功条件: h = h' 。

如果两个散列值相等,那么验签成功,消息(m)被认为是完整的,且确实来自声称的发送方。如果不一致,就是验签失败,消息可能被篡改,或者签名是伪造的。

现实中的算法会复杂非常多,比如RSA,ECDSA等,还涉及到填充方案,随机数生成,数据编码等。


2. 支付系统为什么一定要做签名验签

银行怎么判断扣款请求是从确定的支付平台发出来的,且数据没有被篡改?商户不承认发送过某笔交易怎么办?这都是签名验签技术的功劳。

签名验签主要解决3个问题:

  1. 身份验证:确认支付信息是由真正的发送方发出,防止冒名顶替。

如果无法做身份验证,支付宝就无法知道针对你的账户扣款99块的请求是真实由你楼下小卖部发出去的,还是我冒充去扣的款。

  1. 完整性校验:确认支付信息在传输过程中未被篡改,每一笔交易都是完整、准确的。

如果无法校验完整性,那么我在公共场景安装一个免费WIFI,然后截获你的微信转账请求,把接收者修改成我的账号,再转发给微信,微信就有可能会把钱转到我的账号里。

  1. 防抵赖性:避免任何一方否则曾经进行过的交易,提供法律证据支持。

比如微信支付调用银行扣款100块,银行返回成功,商户也给用户发货了,几天后银行说这笔扣款成功的消息不是他们返回的,他们没有扣款。而签名验签就能让银行无法抵赖。


揭密支付安全:为什么你的交易无法被篡改_签名_02

流程:

  1. 双方先交换密钥,可以通过线下邮件交换,也可以通过线上自助平台交换。
  2. 请求方发出交易报文前使用自己的私钥进行签名,接收方接收报文后先进行验签,验签通过后再进行业务处理。
  3. 接收方处理完业务,返回前使用自己的私钥进行签名,请求方接收返回报文后先进行验签,验签通过后再进行业务处理。


3. 安全签名验签算法推荐

安全一直是一个相对的概念,很多曾经是安全的算法,随着计算机技术的发展,已经不安全了,以后到了量子计算的时代,现在大部分的算法都将不再安全。

一般而言,安全同时取决于算法和密钥长度。比如SHA-256就比MD5更安全,RSA-2048就比RSA-1024更安全。


已经被认为不安全的算法有MD5、SHA-1等算法,容易受到碰撞,不应该在支付系统中使用。

仍然被认为是安全的算法有:SHA-256,SHA-3, RSA-1024,RSA-2048,ECDSA等

当前最常见推荐的算法是RSA-2048。RSA-1024以前使用得多,但因为密钥长度较短,也已经不再推荐使用。


SHA-256只是一种单纯的散列算法,其实是不适合做签名验签算法的,因为需要双方共用一个API密钥,一旦泄露,无法确认是哪方被泄露,也就是只解决了完整性校验,无法解决身份验证和防抵赖性。但因为使用简单,国内外仍然有不少的支付公司公司在大量使用。


4. 常见签名验签算法核心代码

下面以RSA(SHA256withRSA)为例,示例代码如下:

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSASignatureUtil {
    
    // 使用私钥对数据进行签名
    public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(priKey);
        signature.update(data);
        return signature.sign();
    }

    // 使用公钥验证签名
    public static boolean verify(byte[] data, byte[] publicKey, byte[] signatureBytes) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(pubKey);
        signature.update(data);
        return signature.verify(signatureBytes);
    }
}

签名输出是字节码,还需要编码,一般是base64。


如果使用SHA-256(很多公司仍在使用,但不推荐),如下:

import java.security.MessageDigest;

public class SHA256Util {

    // 使用SHA-256对数据进行散列
    public static byte[] hash(byte[] data) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        return digest.digest(data);
    }
}

这里data已经是加了API密钥(也称为API KEY)。所谓的API密钥,就是交易双方共享的一个密钥,这样双方生成的哈希值才会一致。


5. 联调中常见的问题

不管是与商户的联调,还是与支付渠道(或银行)之间的联调,签名验签都是非常耗费精力的环节。验签不通过通常有以下几个情况:

  1. 密钥不匹配:双方以为自己都配置了正确的密钥,但实际没有。
  2. 数据编码不一致:比如一方使用GBK,一方使用UTF-8。
  3. 原始数据选择不一致:比如接口文档要求拼接10个字段,但是代码实现却只拼接了9个字段。或者一方没有把空值放入计算,另一方把空值也放入计算。
  4. 原始数据排序方式不一致:比如接口要求按key的升序排列,调用方却忘记排序就进行签名。
  5. 字符转义不一致:特殊字段的转义必须保持一致。

解决上述问题的最好办法,就是让服务提供方提供一段示例代码,以及示例报文+示例签名,然后在本地使用main方法先跑成功,再移植到项目代码中


6. 结束语

本章主要讲了签名验签名的概念,对于支付系统的重要性,以及常见签名验签名算法及JAVA代码实现。

但是还有一个同样非常重要的问题没有讲:如何安全储存密钥?如果密钥放在代码里或数据库里,开发人员是可以直接获得的,如果不小心泄露出去怎么办?

应对的解决方案就是创建一个密钥中心专门负责密钥的管理,无论加密解密还是签名验签,全部调用密钥中心来处理,业务系统不接触密钥明文

那又来了一个新的问题:这个密钥中心如何设计和实现,才能既保证很高的安全性,又能有非常高的性能表现呢?

后面有机会再开一个密钥中心的设计和实现专题来聊。

标签:揭密,RSA,验签,算法,密钥,支付,篡改,签名
From: https://blog.51cto.com/u_16485618/9058011

相关文章

  • java 微信公众号支付 签名失败
    Java微信公众号支付签名失败解决方案引言在开发微信公众号支付功能时,签名失败是一个常见的问题。本文将为刚入行的开发者介绍解决这个问题的具体步骤,包括整个流程的梳理、每一步需要做什么以及具体的代码实现。流程图flowchartTDA[开始]-->B[获取支付参数]B-->......
  • 面试官:做过支付资产?那先聊聊热点账户吧
    背景当前形势不佳,在这种情况下。小猫更是雪上加霜,他被裁了。投了个把月简历,终于约到一个面试。面试官翻了一下简历:“看你简历上写了支付和账户相关项目,那能否聊一下热点账户问题你们是咋处理的吧”。小猫懵逼了一会,“额?什么是热点账户?我们好像模型里面就一个资产账户,然后充值的......
  • 聚合支付项目-21
    3.4资质申请3.4.1商户服务-资质申请(接口②)3.4.1.1接口定义1、接口描述 1)接收资质申请信息,更新商户信息及审核状态(待审核) 2)返回结果2、接口定义如下:在MerchantService中定义applyMerchant接口/***资质申请接口*@parammerchantId商户id*@parammerchantDTO资质申......
  • 修复HTTP动词篡改导致的认证旁路问题的方法
    本文于2016年4月完成,发布在个人博客网站上。考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。诡异的问题分析AppScan扫描报告的时候,发现报告里提示“HTTP动词篡改导致的认证旁路”,一个名字很长,很怪异的问题。咨询度娘没有获取到必要的信息,于是只......
  • 面试官:做过支付资产?那先聊聊热点账户吧
    背景当前形势不佳,在这种情况下。小猫更是雪上加霜,他被裁了。投了个把月简历,终于约到一个面试。面试官翻了一下简历:“看你简历上写了支付和账户相关项目,那能否聊一下热点账户问题你们是咋处理的吧”。小猫懵逼了一会,“额?什么是热点账户?我们好像模型里面就一个资产账户,然后充值的......
  • 3.《图解支付系统设计与实现》之业务ID生成规范
    这是《图解支付系统设计与实现》系统文章中的第(3)篇。本章主要讲清楚支付系统中为什么要有业务ID,各子域的业务ID为什么要统一规范,以及最佳实践。1.什么是业务ID数据库一般都会设计一个自增ID做为主键,同时还会设计一个能唯一标识一笔业务的ID,这就是所谓的业务ID(也称业务键)。比如收单......
  • 面试官:做过支付资产?那先聊聊热点账户吧
    背景当前形势不佳,在这种情况下。小猫更是雪上加霜,他被裁了。投了个把月简历,终于约到一个面试。面试官翻了一下简历:“看你简历上写了支付和账户相关项目,那能否聊一下热点账户问题你们是咋处理的吧”。小猫懵逼了一会,“额?什么是热点账户?我们好像模型里面就一个资产账户,然后充值的......
  • 《图解支付系统设计与实现》之基本概念与设计概要
    这是《图解支付系统设计与实现》系列文章的第一篇。本系列文章是偏实战的,本章内容讲清楚支付系统是什么,主要解决什么问题,部分核心流程,以及一些后面会频繁使用到的术语。至于支付起源,在线支付发展历程等知识,感兴趣的同学可以参考网络上其它文章或书籍。欢迎转载转发,转载请注明出处。......
  • 《图解支付系统设计与实现》之详解收单结算拒付
    这是《图解支付系统设计与实现》系统文章中的第(2)篇。本章主要讲清楚支付系统中收单结算涉及的基本概念,产品架构、系统架构,以及一些核心的流程和相关领域模型、状态机设计,并顺便讲讲和收单结算非常紧密的拒付。收单结算是支付系统最重要的子域之一,行业内经常把有牌照的支付平台称为......
  • 聚合支付项目-20
    3商户资质申请3.1需求分析3.1.1系统交互流程交互流程如下:前端上传证件照片,请求商户平台应用。商户平台应用请求阿里云上传图片。上传成功返回图片标识给前端。前端携带证件图片标识和资质申请信息提交到商户平台应用。请求商户服务保存资质申请。保存成功返回给前端。商户资......