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 确实正确地反映了嵌入实际换行符的环境变量,如以下bash
sn-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 中"..."
字符串中原样。
"..."
字符串 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
,请使用以下技术之一:
bash
、ksh
、zsh
:使用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"
将不会在 hey
和 man
之间创建换行符。使用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中包含换行符的环境变量?的主要内容,如果未能解决你的问题,请参考以下文章