首页 > 解决方案 > Node.js + 加密签名并通过 express 验证数据

问题描述

我希望能够确保公钥和私钥是有效的。我会将公钥存储在服务器上,而不是用户上传的每个请求。但是,将不允许发送。

server.js(服务器)

const express = require('express')
const crypto = require("crypto")
const fetch = require("node-fetch")
const app = express()
const port = 3002

app.get('/', async (req, res) => {
    var res2 = await fetch('http://localhost:3001/data')
    var verifiableData = await res2.text()

    var res2 = await fetch('http://localhost:3001/key')
    var publicKey = await res2.text()

    var res2 = await fetch('http://localhost:3001/sig')
    var signature = await res2.text()


    const isVerified = crypto.verify(
        "sha256",
        Buffer.from(verifiableData),
        {
            key: publicKey,
            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
        },
        signature
    )
    
    res.send(isVerified)
})

app.listen(port, () => {
    console.log(`Listening at http://localhost:${port}`)
})

index.js(客户端)

const express = require('express')
const crypto = require("crypto")
const app = express()
const port = 3001

const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
    // The standard secure default length for RSA keys is 2048 bits
    modulusLength: 2048,
})

const verifiableData = "this need to be verified"

const signature = crypto.sign("sha256", Buffer.from(verifiableData), {
    key: privateKey,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
})

app.get('/data', (req, res) => {
    res.send(verifiableData)
})

app.get('/sig', (req, res) => {
  res.send(signature.toString("base64"))
})

app.get('/key', (req, res) => {
    res.send(publicKey)
})

app.listen(port, () => {
    console.log(`Listening at http://localhost:${port}`)
})

我知道我应该从服务器而不是客户端请求信息,但我只是想让它工作。

我在 server.js 代码中遇到了这个错误signature

(node:19312) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "signature" argument must 
be an instance of Buffer, TypedArray, or DataView. Received type string ('OFEush86vZIuFnTLFBiFt4Be...)
    at Object.verifyOneShot [as verify] (internal/crypto/sig.js:212:11)
    at C:\Users\user\Documents\coding\nodestuff\stesting\server\server.js:20:31
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:19312) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:19312) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise 
rejections that are not handled will terminate the Node.js process with a non-zero exit code.

将 index.js 更新为

app.get('/sig', (req, res) => {
  res.send(signature.toString("base64"))
})

和 server.js 到

const isVerified = crypto.verify(
        "sha256",
        Buffer.from(verifiableData),
        {
            key: publicKey,
            padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
        },
        Buffer.from(signature, 'base64')
    )

然后得到这个错误:

(node:5580) UnhandledPromiseRejectionWarning: Error: error:0909006C:PEM routines:get_name:no start line
    at Object.verifyOneShot [as verify] (internal/crypto/sig.js:219:10)
    at C:\Users\user\Documents\coding\nodestuff\stesting\server\server.js:20:31
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:5580) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:5580) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

它在单个文件中工作得非常好,只是在通过快速 API 发送时不起作用。如何修复错误/错误?

标签: node.jsexpress

解决方案


需要做的是publicKey无效。这是因为它的PublicKeyObject含义是不会使用 express 发送,而将值保留为{}

我必须做

const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
    // The standard secure default length for RSA keys is 2048 bits
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    modulusLength: 2048,
})

以及在签名部分使用它。

Buffer.from(signature, 'base64')

推荐阅读