美文网首页
Node.js 上的 SHA256WithRSA 其实好简单

Node.js 上的 SHA256WithRSA 其实好简单

作者: Kenny锅 | 来源:发表于2019-06-24 23:16 被阅读0次

    只要项目大一点或者跟金融沾点边,都要考虑数据传输的安全性。

    「用 POST 请求」。对,这是入门级的安全措施。还有没有高级一点的?(想要 GET 请求安全也不是不可能)

    「那就用 HTTPS传输」。很对,这是一个非常重要的方案,这已经是中级的安全方案。

    有没有中高级的安全方案?有,就是数据签名与验签。如果对接过支付宝支付、微信支付的朋友都很熟悉,如果没有对接过,我就跟大家聊聊。

    我知道大家都很忙,没有时间听我啰嗦,我先把核心代码放出来,你先把功能实现了,回过头来细细听我唠叨。

    一、private key 和 public key

    大家可以通过如下这个网站生成 private key 和 public key(或者直接用我粘出来的两个 key 也行):http://web.chacuo.net/netrsakeypair

    const privateKeyString = `
    -----BEGIN PRIVATE KEY-----
    MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIYSs8zydPxowvlnX+9vyDRS52nNwQocDcmpXyVfMY5F+1UdmVcktwbWAzjpAZHlmNjtSYYxMkp1jedDCFBVvcQGu1ulbT7yvGY8FFRfMG0UbXT7m3hUK6IHCVYUWKCGI2+HI44V26O+pq/KvIY96Oy+X1zZa1cv2aEb3GFnH+D1AgMBAAECgYAq8li4AL5qkCBMhcmcSCFIaXoJUUhRtbTQ8TkyHnEgUth0ZlvVJ0SdovY7R6AiHPq+GhxgKOgkI83F05oZKa30YUXY5MVhUYbBvjeifbTG3lIeDwL1s51nRIUBcGEyfnDfotePtt4quxV5cXNUcsNVymgA7Pin/6bGsc062ZsQgQJBAN6VGh39fDVzqHqhPpf4WsgOvmSC5RzPMobNEP0lU9SNat86Othg6tz3h3u3vRNsXMu+n+9F5oRFbJobiXhlt6ECQQCaM8P3bYpKwImAm0gmUixIoF0wwlnYm7PHcr5P1hYHrMvxS7dT5PdHKihJAnIYhtLG6bfdzFv/Kb4XP0Gf5xjVAkBLOk2XcUL3td1thO3o4xGbqBAFXJAfCpBjKw/g3yrUHe/O/plA5JC8mhR6ZgFLfUZnvkfD0PY2IliwRTpTLN3BAkBSxAYjAACCLuWeybnoF6L9OFXMngRrZucP3l6Xq2kXpX+xe9pihTrUT6Rfy5hB4duwODIgMlgOlPEauTEYCoohAkEAgmSF5pYELbvOW9eO9tQrFm20qf/9sXHi1Z87qSzGxA3HqcrqPe73L3nfxg5nrgOwg0ZqNl1wNBXti+LxXa7DeQ==
    -----END PRIVATE KEY-----
    `
    
    const publicKeyString = `
    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGErPM8nT8aML5Z1/vb8g0UudpzcEKHA3JqV8lXzGORftVHZlXJLcG1gM46QGR5ZjY7UmGMTJKdY3nQwhQVb3EBrtbpW0+8rxmPBRUXzBtFG10+5t4VCuiBwlWFFighiNvhyOOFdujvqavyryGPejsvl9c2WtXL9mhG9xhZx/g9QIDAQAB
    -----END PUBLIC KEY-----
    `
    

    注意:

    • 1、如果你公司的后端合适的是 Java 语言,就使用「PKCS8」密钥格式,也叫 「PKCS#8」,如果非 Java 语言可以考虑「PKCS1」。
    • 2、Java 使用private key 和 public key时,要把首尾「-----BEGIN PRIVATE KEY-----」之类的删除,但在 JavaScript 里使用时,一定要加上,后面会细讲原因。

    二、前端(APP端)加密

    一般都是大前端使用 private key 生成加密数据 ,传给后端接口,后端使用 public key 验证加密信息,所以我只需要准备编写如下代码即可:

    import { KEYUTIL, KJUR, hextob64, hextob64u } from 'jsrsasign';
    
    const privateKeyString = `
    -----BEGIN PRIVATE KEY-----
    MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIYSs8zydPxowvlnX+9vyDRS52nNwQocDcmpXyVfMY5F+1UdmVcktwbWAzjpAZHlmNjtSYYxMkp1jedDCFBVvcQGu1ulbT7yvGY8FFRfMG0UbXT7m3hUK6IHCVYUWKCGI2+HI44V26O+pq/KvIY96Oy+X1zZa1cv2aEb3GFnH+D1AgMBAAECgYAq8li4AL5qkCBMhcmcSCFIaXoJUUhRtbTQ8TkyHnEgUth0ZlvVJ0SdovY7R6AiHPq+GhxgKOgkI83F05oZKa30YUXY5MVhUYbBvjeifbTG3lIeDwL1s51nRIUBcGEyfnDfotePtt4quxV5cXNUcsNVymgA7Pin/6bGsc062ZsQgQJBAN6VGh39fDVzqHqhPpf4WsgOvmSC5RzPMobNEP0lU9SNat86Othg6tz3h3u3vRNsXMu+n+9F5oRFbJobiXhlt6ECQQCaM8P3bYpKwImAm0gmUixIoF0wwlnYm7PHcr5P1hYHrMvxS7dT5PdHKihJAnIYhtLG6bfdzFv/Kb4XP0Gf5xjVAkBLOk2XcUL3td1thO3o4xGbqBAFXJAfCpBjKw/g3yrUHe/O/plA5JC8mhR6ZgFLfUZnvkfD0PY2IliwRTpTLN3BAkBSxAYjAACCLuWeybnoF6L9OFXMngRrZucP3l6Xq2kXpX+xe9pihTrUT6Rfy5hB4duwODIgMlgOlPEauTEYCoohAkEAgmSF5pYELbvOW9eO9tQrFm20qf/9sXHi1Z87qSzGxA3HqcrqPe73L3nfxg5nrgOwg0ZqNl1wNBXti+LxXa7DeQ==
    -----END PRIVATE KEY-----
    `
    
    export function sha256withRSA(inputString) {
        const key = KEYUTIL.getKey(privateKeyString);
        // 创建 Signature 对象,设置签名编码算法
        const signature = new KJUR.crypto.Signature({ alg: 'SHA256withRSA' });
        // 初始化
        signature.init(key);
        // 传入待加密字符串
        signature.updateString(inputString);
        // 生成密文
        const originSign = signature.sign();
        // const sign64 = hextob64(originSign);
        // console.log('sign base64 =======', sign64);
        // const sign64u = hextob64u(originSign);
        // console.log('sign base64u=======', sign64u);
        return originSign;
    }
    

    把 public key 给后端同事,注意:不要带首尾 ----- 两行。

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGErPM8nT8aML5Z1/vb8g0UudpzcEKHA3JqV8lXzGORftVHZlXJLcG1gM46QGR5ZjY7UmGMTJKdY3nQwhQVb3EBrtbpW0+8rxmPBRUXzBtFG10+5t4VCuiBwlWFFighiNvhyOOFdujvqavyryGPejsvl9c2WtXL9mhG9xhZx/g9QIDAQAB
    

    到这儿,差不多就可以了收工了。

    ------------------------------- 好奇少年分割线 -------------------------------

    三、jsrsasign API 简介

    3.1 谁加密,谁验证?

    发起方 动作 key
    大前端 加密 用 private key
    大前端 验证加密 用 public key
    后端 加密 用 private key
    后端 验证加密 用 public key

    3.2 KEYUTIL, KJUR, hextob64, hextob64u 分别都是什么

    3.3 KEYUTIL.getKey 作用

    API:KEYUTIL.getKey(param, passcode, hextype)
    param:通过入参获取 private key 或 public key 对象
    passcode:传入 private key 或 public key 生成时的密码(可选参数)
    hextype: 传入pkcs8prvpkcs5prvpkcs8pubx509pub 之类的值(可选参数)
    更多详情:https://kjur.github.io/jsrsasign/api/symbols/KEYUTIL.html#.getKey

    3.4 KJUR.crypto.Signature 作用

    KJUR.crypto.Signature 非常简单的「模拟」了 java.security.Signature 类,跟 Java 一样,在 new 时给 constructor 传参
    API:KJUR.crypto.Signature(param)

    • param 是一个对象,格式为:{ alg: 'SHA256withRSA' } 或 { alg: 'SHA256withRSA', prov: 'cryptojs/jsrsa' }
    • alg 参数支持如下算法:
    MD5withRSA - cryptojs/jsrsa
    SHA1withRSA - cryptojs/jsrsa
    SHA224withRSA - cryptojs/jsrsa
    SHA256withRSA - cryptojs/jsrsa
    SHA384withRSA - cryptojs/jsrsa
    SHA512withRSA - cryptojs/jsrsa
    RIPEMD160withRSA - cryptojs/jsrsa
    MD5withECDSA - cryptojs/jsrsa
    SHA1withECDSA - cryptojs/jsrsa
    SHA224withECDSA - cryptojs/jsrsa
    SHA256withECDSA - cryptojs/jsrsa
    SHA384withECDSA - cryptojs/jsrsa
    SHA512withECDSA - cryptojs/jsrsa
    RIPEMD160withECDSA - cryptojs/jsrsa
    MD5withRSAandMGF1 - cryptojs/jsrsa
    SHA1withRSAandMGF1 - cryptojs/jsrsa
    SHA224withRSAandMGF1 - cryptojs/jsrsa
    SHA256withRSAandMGF1 - cryptojs/jsrsa
    SHA384withRSAandMGF1 - cryptojs/jsrsa
    SHA512withRSAandMGF1 - cryptojs/jsrsa
    RIPEMD160withRSAandMGF1 - cryptojs/jsrsa
    SHA1withDSA - cryptojs/jsrsa
    SHA224withDSA - cryptojs/jsrsa
    SHA256withDSA - cryptojs/jsrsa
    

    2.5 signature.init(key) 作用

    • init(key, pass) - 用密钥来初始化此对象,用于后面的加密或验签工作。只需指定密钥,该方法就会调用 KEYUTIL 类初始化它。
      • key - 可以传下述类型参数:

        • PEM 格式的 PKCS#8 加密 RSA/ECDSA private key 必须包含 "BEGIN ENCRYPTED PRIVATE KEY"
        • PEM 格式的 PKCS#5 加密 RSA/DSA private key 必须包含 "BEGIN RSA/DSA PRIVATE KEY" 和 ",ENCRYPTED"
        • PEM 格式的 PKCS#8 字符串 RSA/ECDSA private key 必须包含 "BEGIN PRIVATE KEY"(注:例子中我采用的是这种,因为 jsrsasign 要求必传
        • PEM 格式的 PKCS#5 字符串 RSA/DSA private key 必须包含 "BEGIN RSA/DSA PRIVATE KEY" 但没有 ",ENCRYPTED"
        • RSAKey 对象 private key
        • KJUR.crypto.ECDSA 对象 private key
        • KJUR.crypto.DSA 对象 private key
      • pass - 传入生成 private key 和 public key 时的密码,可选参数

    2.6 signature.updateString(inputString) 作用

    • signature.updateString(inputString) - 用于更新原字符串为签名或验证的字符串,这里还没有生成密文。

    2.7 signature.sign() 作用

    • signature.sign() - 以十六进制字符串形式返回数据更新的签名,到就可以跟后端同事联调了。

    2.8 hextob64(originSign) 作用

    • hextob64(originSign) - 将十六进制字符串签名转换为 Base 64,这样是为了方便传输(十六进制的签名有4k,但 Base 64 签名只有 2k )

    参考:

    全文完,谢谢阅读!

    相关文章

      网友评论

          本文标题:Node.js 上的 SHA256WithRSA 其实好简单

          本文链接:https://www.haomeiwen.com/subject/scgaqctx.html