Node中包含换行符的环境变量?

Posted

技术标签:

【中文标题】Node中包含换行符的环境变量?【英文标题】:Environment variables containing newlines in Node? 【发布时间】:2015-08-04 16:35:47 【问题描述】:

我正在尝试使用环境变量将 RSA 私钥加载到我的 nodejs 应用程序中,但换行符似乎正在自动转义。

对于以下内容,假设 PRIVATE_KEY env var 设置为以下内容(不是我的实际密钥):

PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp\nwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5\n1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh\n3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2\npIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX\nGukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il\nAkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF\nL0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k\nX6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl\nU9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ\n37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=\n-----END RSA PRIVATE KEY-----"

如果我直接使用前面的字符串调用console.log,我会得到以下输出:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----

您可以看到换行符受到尊重。但是,如果我调用 console.log(process.env["PRIVATE_KEY"]),输出将包含 \n 文字而不是实际的换行符:

-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp\nwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5\n1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh\n3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2\npIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX\nGukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il\nAkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF\nL0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k\nX6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl\nU9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ\n37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=\n-----END RSA PRIVATE KEY-----

我一直试图在网上找到更多关于节点如何处理环境变量的信息,但没有运气。如何在保持换行符的同时通过 env vars 加载此密钥?如果这不可能,我该如何恢复它们?

【问题讨论】:

【参考方案1】:

在使用值之前替换\n

var private_value = process.env.PRIVATE_KEY.replace(/\\n/g, '\n');
console.log(private_value);

会得到正确的结果:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----

【讨论】:

你是个天才!如此简单完美! 假设您可以控制应用程序代码。 太棒了!辛比工作。就我而言,我使用 ("$System.env.SIGNING_KEY_ID".replace(/\n/, '\n')) 搞定了。 这行得通,但我不明白如何。 ?它正在用\n 替换\n @NikhilOwalekar 它将 \\n 替换为 \n。我遇到了(感谢@Adriano)我的 AWS lambda 函数和 env var 的问题。【参考方案2】:

dotenv 支持双引号换行:

双引号值扩展新行

MULTILINE="new\nline" 变为

MULTILINE: 'new
line'

【讨论】:

这绝对是公认的答案。简单且有文档记录。【参考方案3】:

如果您使用 dotenv:我们通过换行符和 JSON.parse 以这种方式解决了它(这允许字符串中的任何反斜杠转义字符,而不仅仅是 \n强>):

在 .env 中:

MY_KEY='-----BEGIN CERTIFICATE-----\nabcde...'

在 server.ts 中:

myKey = JSON.parse(`"$process.env.MY_KEY"`), // convert special chars

查看帖子:https://github.com/motdotla/dotenv/issues/218

【讨论】:

我使用了这段代码一段时间,但它突然停止工作并开始在 JSON 中的位置 32 错误处显示 Unexpected token,该错误指向 \ 获取Unexpected token =【参考方案4】:

Node.js 确实正确地反映了嵌入实际换行符的环境变量,如以下bashsn-p所示:

$ PRIVATE_KEY=$'ab\ncde' node -p 'process.env["PRIVATE_KEY"].indexOf("\n")'
2  # 0-based index of the (first) actual newline char. in env. var. 'PRIVATE_KEY'

注意$'...'bash字符串的一种特殊类型,其中\n等转义序列是扩展的,所以在上面的命令中确实定义了PRIVATE_KEY 2 行并作为环境变量传递给node(只需在要调用的命令之前添加变量赋值,这是类 POSIX shell 中的标准功能)。

打印环境变量值的简单方法逐字是:

# With *verbatim* '\n'
$ X='line 1\nline 2' node -p 'process.env.X'
line1\nline 2

# With *actual newline*, thanks to $'...' interpolation.
$ X=$'line 1\nline 2' node -p 'process.env.X'
line 1
line 2

事实上,Node 不会以任何方式解释环境变量的值(这是正确的做法)。

一定是您的PRIVATE_KEY 变量不包含实际的换行符,而是\n 文字\ 字符。后跟字符。n)。

如果问题中的赋值命令PRIVATE_KEY="..."shell 命令,则可以解释:在bash\n 等类似POSIX 的shell 中"..." 字符串中原样

相比之下,javascript "..." 字符串 do 插入转义序列,例如 \n,这就是为什么将这样的字符串直接传递给 console.log() 确实会输出换行符;例如,node -e 'console.log("ab\ncde")' 确实输出 2 行。

PRIVATE_KEY="ab\ncde" node -p 'process.env["PRIVATE_KEY"]'(字面意思)输出ab\ncde,表明\n 被保留为文字。

您有两种选择来解决您的问题:

最好用实际的换行符来定义您的环境变量 - 见下文。

或者,如果您不控制环境变量的设置方式,请将 \n 文字扩展为 Node.js (JavaScript) 代码中的实际换行符:请参阅 Adriano Godoy's helpful answer。 p>


在类似 POSIX 的 shell 中使用实际换行符定义 PRIVATE_KEY,请使用以下技术之一:

bashkshzsh:使用ANSI C-quoted string:
export PRIVATE_KEY=$'-----BEGIN RSA PRIVATE KEY-----\n....\n-----END RSA PRIVATE KEY-----'
其他,例如dash(以及来自任何使用sh的shell脚本):
export PRIVATE_KEY="$(printf %s '-----BEGIN RSA PRIVATE KEY-----\n....\n-----END RSA PRIVATE KEY-----')"

或者,为了更好的可读性,您可以使用带有 here-document 的命令替换:

export PRIVATE_KEY="$(cat <<'EOF'
-----BEGIN RSA PRIVATE KEY-----
...
...
-----END RSA PRIVATE KEY-----
EOF
)"

最后,正如Allen Luce's answer shows,POSIX 兼容的 shell 甚至允许 常规字符串文字 跨越多行,尽管可读性可能会受到一些影响:

export PRIVATE_KEY='-----BEGIN RSA PRIVATE KEY-----
...
...
-----END RSA PRIVATE KEY-----'

【讨论】:

感谢您成为唯一真正解释正在发生的事情的答案。【参考方案5】:

通过检查而不是打印可能更容易了解实际情况:

% export X="hey\nman"
% node
> process.env['X']
'hey\\nman'
>

Node 的 REPL 隐式应用 util.inspect 方法,该方法发出一个转义字符串。这显示了环境变量包含的文字反斜杠和小写“n”。所以被送到console.log 的内容更像是这样的:

> console.log("hey\\nman")
hey\nman

一个选项(在大多数流行的 shell 中)是通过在带引号的字符串中按 enter 将换行符直接嵌入到变量中:

% export X="hey
> man"
% node
> process.env['X']
'hey\nman'
> console.log(process.env['X'])
hey
man
undefined
>

此技术也适用于脚本文件,只需在引号内使用换行符。如果您必须按原样获取环境变量,一种常见的方法是使用字符串替换:

% export X="hey\nman\ndude\nwhat"
% node
> console.log(process.env['X'].replace(/\\n/g, '\n'))
hey
man
dude
what

【讨论】:

++,但短语“节点将...转义它们以避免插值”具有误导性并暗示了一种误解。 Node 不会 - 也不应该 - 将字符串插值应用于环境变量。您看到的转义是 Node REPL 的工件:当您仅通过提交打印字符串或变量时,没有console.log(),REPL 此时主动将值编码为 JavaScript字符串以便在 JavaScript 源代码中重用。因此,如果 REPL 显示 a\\nb,则意味着字符串 literally 包含 \n(即字符 \ n)。 提示符。 (%) 在您的 shell 代码中建议使用 csh,但使用 export 建议使用类似 POSIX 的 shell。在类似 POSIX 的 shell 中,"hey\nman"不会heyman 之间创建换行符。使用echo 打印值会混淆图片,因为在某些类似POSIX 的shell 中echo 确实解释了转义序列。按原样打印值的外壳中立方式是printf %s "$X"。重申前一点:无论 shell 分配的值是什么,Node.js 都将使用 uninterpreted (即使 Node.js REPL 可能会为 display 目的应用转义) . 不确定你认为我在说"hey\nman" 是如何创建换行符的,我正在证明它没有。关于echo 的观点很好,所以我删除了它。还澄清了 Node 如何转义字符串。 在文字 \n 与实际换行符之间存在混淆,这可以从您删除后的 echo $X 示例中得到证明。我很高兴你删除了它。一种从图片中提取诊断输出并逐字回显值的简单方法:X='hey\nman' node -p 'process.env.X'X=$'hey\nman' node -p 'process.env.X'【参考方案6】:

如另一个主题中所述,您可以将多行字符串编码为 base64 并将其放入 .env 中

HTTPS_CA_CERTIFICATE=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURDVENDQWZHZ0F3SUJBZ0lVY29lWFp1R

然后在您的应用程序中对其进行解码

var cert = new Buffer(process.env.HTTPS_CA_CERTIFICATE, 'base64').toString('ascii');

【讨论】:

【参考方案7】:

我正在使用:

JSON.parse(`"$process.env.PUBPEM"`)

突然开始失败。 所以我把它改成:

JSON.parse(JSON.stringify(process.env.PUBPEM))

这为我解决了。

【讨论】:

【参考方案8】:

为了任何尝试在 dotenv 文件中使用多行变量(即 RSA 私钥)的人的利益(但应该适用于任何配置文件)。

1) 使私钥的每一行都以 \n

结尾
  such that first line**\n**
  second line**\n**
  and the  third line and so on

2) 现在用双引号将变量放在单行中,如下所示 KEY="这样第一行**\n第二行\n第三行以此类推\n**"

3) 确保您也为键添加前导和尾随 \n 字符 KEY="\n第一行**\n第二行\n第三行以此类推\n**"

4) 现在在您的代码中(即节点,当然,如果您无权访问您依赖平台/应用程序的行为的代码)

goodlyRepresentedKey = (process.env.KEY).replace(/\n/g, '\n');

(如果很大,为什么不好)

【讨论】:

以上是关于Node中包含换行符的环境变量?的主要内容,如果未能解决你的问题,请参考以下文章

shell 变量名中包含变量怎么弄

环境变量

Postman第4篇—变量的使用

java环境变量

java环境变量的配置

java环境变量的配置