从 Node.js 应用程序查询 Heroku 托管的 Postgres 数据库期间出现“自签名证书”错误

akz*_*har 39 javascript postgresql heroku node.js

我的 Node.js 应用程序能够通过npm pg模块使用本地 Postgres 数据库。我也可以通过命令行和heroku pg:psql命令连接到 Heroku 托管的 Postgres 数据库(免费的业余爱好开发计划)。 但是当我的 Node.js 应用程序尝试查询 Heroku 托管的 Postgres 数据库时,我收到一个self signed certificate错误。

这是有self signed certificate错误的输出:

(node:2100) UnhandledPromiseRejectionWarning: Error: self signed certificate
    at TLSSocket.onConnectSecure (_tls_wrap.js:1051:34)
    at TLSSocket.emit (events.js:189:13)
    at TLSSocket._finishInit (_tls_wrap.js:633:8)
(node:2100) 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(). (rejection id: 1)
(node:2100) [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.
D:\MY\DEV\PROJECTS\AdsSubscribeBot\test.js:57
  if (err) throw err;
           ^

Error: Connection terminated unexpectedly
    at Connection.con.once (D:\MY\DEV\PROJECTS\AdsSubscribeBot\node_modules\pg\lib\client.js:264:9)
    at Object.onceWrapper (events.js:277:13)
    at Connection.emit (events.js:189:13)
    at Socket.<anonymous> (D:\MY\DEV\PROJECTS\AdsSubscribeBot\node_modules\pg\lib\connection.js:76:10)
    at Socket.emit (events.js:194:15)
    at TCP._handle.close (net.js:597:12)
Run Code Online (Sandbox Code Playgroud)

重现此错误的最简单方法是尝试使用示例代码从 Heroku 开发中心连接 Node.js:https ://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-node-js

这是导致self signed certificate错误的代码示例:

const connectionString = 'postgres://USERNAME:PASSWORD@HOST:PORT/DB_NAME';

const { Client } = require('pg');

const client = new Client({
  connectionString: connectionString,
  ssl: true
});

client.connect();

client.query('SELECT * FROM users;', (err, res) => {
  if (err) throw err;
  for (let row of res.rows) {
    console.log(JSON.stringify(row));
  }
  client.end();
});
Run Code Online (Sandbox Code Playgroud)

也许有人遇到过同样的问题并且知道如何解决它。

在此先感谢您的帮助。

小智 68

检查你的 pg 配置。听起来您正在使用 pg 8,它弃用了隐式禁用证书验证(就像您在配置中将 ssl 设置为 true 但未提供 ssl 配置一样)。指定rejectUnauthorized: true需要有效的 CA 或rejectUnauthorized: false明确选择退出 MITM 保护。

您可以在设置 pg 配置的地方执行此操作,如下所示

const client = new Client({
  connectionString: connectionString,
  ssl: { rejectUnauthorized: false }
})
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,仅设置环境变量有效:`PGSSLMODE=no-verify`(请参阅Heroku文档:https://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-node-js) (7认同)
  • 我必须做这样的事情才能同时用于生产和我的本地机器: `ssl: this.isProduction() ?{ 拒绝未经授权: false } : false` (3认同)
  • 我发现令人惊讶的是,这里几乎每个答案都表明这种不安全的黑客行为使开发人员面临中间人攻击。 (3认同)

Avi*_*ler 15

如果有人在将 SSL 对象附加到客户端对象后仍然遇到此问题,并且他们正在使用连接字符串。确保连接字符串中没有 ssl 参数。如果您使用 Digital Ocean,则此参数包含在生成的连接字符串中。

这就是 Digital Ocean 默认格式化其连接字符串的方式

postgres://USERNAME:PASSWORD@HOST:PORT/DB_NAME:25060/defaultdb?&sslmode=require

  • 绝对必要:在我遇到这个之前我已经浪费了 3 个小时的时间。 (3认同)
  • 啊。是的。我正在使用 Heroku。但同样的问题也存在。我在最后添加了 ?ssl=true 。谢谢! (2认同)

Tom*_*und 15

为了让它发挥作用,我必须添加:

ssl: { rejectUnauthorized: false }
Run Code Online (Sandbox Code Playgroud)

还要其添加到环境中:

NODE_TLS_REJECT_UNAUTHORIZED=0
Run Code Online (Sandbox Code Playgroud)


小智 7

以下是使用 Knex.js 接受的答案的变体。在 Heroku 上测试。

const parse = require('pg-connection-string').parse;
const pgconfig = parse('your-pg-connection-string');
pgconfig.ssl = { rejectUnauthorized: false };

const knex = Knex({
  client: 'pg',
  connection: pgconfig,
});
Run Code Online (Sandbox Code Playgroud)