将请求发送到同一台计算机时无法验证SSL证书
我有一台与Next.js一起运行节点服务器的远程Ubuntu计算机,并使用Next-auth进行身份验证。一切都可以在本地使用HTTP。
配置
这是在HTTPS上运行节点服务器并使用Next.js的代码。
const https = require('https');
const fs = require('fs');
const next = require('next')
const port = 3000;
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, dir: __dirname })
const handle = app.getRequestHandler()
const { parse } = require('url');
const options = {
key: fs.readFileSync('./path/to/private-key'),
cert: fs.readFileSync('./path/to/csr'),
ca: [fs.readFileSync('./path/to/gdroot-g2')]
};
app.prepare().then(() => {
https.createServer(options, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on localhost:${port}`)
})
})
该服务器在端口3000上运行,因此我使用sudo iptables -t nat -a prerouting -p tcp -pport 443 -J redirect -j redirect -to -port 3000
将请求重定向到443。
我购买了一个Deluxe SSL证书已注册为example.com
,还购买了域名,该名称将其指向服务器IP的记录。
这是服务器的/etc/hosts
文件(不包括IPv6主机)。
127.0.0.1 localhost
192.XXX.XXX.XX server.example.com server
在我的.env
中,我设置nextauth_url = https://example.com:3000
,以便它在此处发送其请求。
生产构建中的问题
,当下一个实体尝试获取用户会话时,它会使用域名将HTTPS请求从服务器发送到本身(例如:ex:ex:example.com
)。然后,服务器使用请求到https://mdomain.com:3000/api/auth/session失败,原因:无法验证第一个证书
。
如果我更改nextauth_url = https://example.com
(没有端口),则node in errors in 请求
请求https://example.com/api/auth/auth/session/session/sessive失败,原因:连接Econnrefuse 192.xxx.xxx.xx:443
。
同样,如果我使用curl(curl https://example.com:3000/api/auth/session
),curl响应curl:(60)SSL证书问题:无法获得本地发行者证书
,该请求甚至从未收到节点(因此节点永远不会错误)。
请注意,如果我使用自己的计算机中的卷曲,它将发送请求并接收到该请求,但迅速抛出请求失败,无法验证...
错误(我相信这是因为证书从我到服务器的计算机,但是服务器到服务器的后续请求会导致错误)。
我已经尝试设置
看来问题的根源是当服务器从其本身接收HTTPS请求时,域名不匹配example.com
(也许来自> 127.0.0.1.1:3000
或其IP地址),因此无法验证它。当发件人是另一台计算机时,所有HTTPS请求都可以使用。
我能想到的唯一解决方案是为服务器上的Localhost创建一个自签名证书(然后我可以指出Next-auth在内部使用Localhost)。然后,这将要求服务器使用2个SSL证书,这也可能是不可能的。但是,根据Next-auth的说法,一切都应该与HTTPS一起使用,因此希望我只是做出了可固定的错误配置。
感谢您的任何帮助,如果您对解决方案有任何想法,请告诉我。
更新
我对NextAuth_url_internal进行了更多实验,发现如果我在端口3000上启动HTTPS服务器,在端口3001上启动HTTP服务器,并设置NextAuth_url_internal = http://127.0.0.0.0.1.1:3001
它确实有效。
但是,在端口3001上拥有HTTP服务器(用户仍然可以连接到此端口)并允许Next-auth内部使用HTTP是安全漏洞吗?是否可以拥有nextAuth_url_internal = https://127.0.0.1:3000
和自我签名Localhost的证书?还是那也是脆弱性?
Note that currently, without a self-signed certificate for localhost, if I set NEXTAUTH_URL_INTERNAL=https://127.0.0.1:3000
then node errors with request to https://127.0.0.1 :3000/api/auth/session失败,原因:主机名/ip不匹配证书的altnames:ip:127.0.0.1不在证书列表中:
。也许我可以在Altnames中添加Localhost?还是服务器的IP?
I have a remote Ubuntu machine running a node server with next.js and using next-auth for authentication. Everything works fine with HTTP locally.
Configuration
Here is the code that runs the node server on HTTPS and uses next.js.
const https = require('https');
const fs = require('fs');
const next = require('next')
const port = 3000;
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, dir: __dirname })
const handle = app.getRequestHandler()
const { parse } = require('url');
const options = {
key: fs.readFileSync('./path/to/private-key'),
cert: fs.readFileSync('./path/to/csr'),
ca: [fs.readFileSync('./path/to/gdroot-g2')]
};
app.prepare().then(() => {
https.createServer(options, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on localhost:${port}`)
})
})
The server runs on port 3000, so I used sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 3000
to redirect requests to 443.
I bought a Deluxe SSL certificate registered for example.com
and also bought the domain name, which has an A record pointing it to the server's ip.
Here is the server's /etc/hosts
file (excluding the IPv6 hosts).
127.0.0.1 localhost
192.XXX.XXX.XX server.example.com server
In my .env
, I set NEXTAUTH_URL=https://example.com:3000
in order for it to send its requests there.
The Problem
On the production build, when next-auth attempts to get the user's session, it sends an HTTPS request from the server to itself using the domain name (Ex: example.com
). The server then errors with request to https://mDomain.com:3000/api/auth/session failed, reason: unable to verify the first certificate
.
If I change NEXTAUTH_URL=https://example.com
(without the port), node instead errors with request to https://example.com/api/auth/session failed, reason: connect ECONNREFUSED 192.XXX.XXX.XX:443
.
Similarly, if I use curl (curl https://example.com:3000/api/auth/session
), curl responds with curl: (60) SSL certificate problem: unable to get local issuer certificate
and the request is never even received by node (so node never errors).
Note that if I use curl from my own machine, it sends the request and node receives it but promptly throws the request failed, unable to verify...
error (I believe this is because the certificate works from my machine to the server, but the subsequent request from the server to the server causes the error).
I have tried setting NEXTAUTH_URL_INTERNAL but the error is the same (I have tried setting it to the domain name, ip address, and localhost). However, I do not think this is the actual root of the issue.
It appears that the root of the problem is that when the server receives an HTTPS request from itself, the domain name doesn't match example.com
(perhaps it comes from 127.0.0.1:3000
or its ip address) and therefore it is unable to verify it. All HTTPS requests work when the sender is another machine.
The only solution I can think of is creating a self-signed certificate for localhost on the server (then I could point next-auth to use localhost internally). That would then require the server to use 2 SSL certificates, which might not be possible either. According to next-auth, however, everything should work fine with HTTPS so hopefully, I have just made a fixable misconfiguration.
Thank you for any help and please let me know if you have any ideas for solutions.
Update
I experimented more with NEXTAUTH_URL_INTERNAL and discovered that if I start an HTTPS server on port 3000 and an HTTP server on port 3001 and set NEXTAUTH_URL_INTERNAL=http://127.0.0.1:3001
it does work.
However, wouldn't it be a security vulnerability to have an HTTP server on port 3001 (users can still connect to this port) and to allow next-auth to internally use HTTP? Would it be possible to have NEXTAUTH_URL_INTERNAL=https://127.0.0.1:3000
and self-sign a certificate for localhost? Or would that also be a vulnerability?
Note that currently, without a self-signed certificate for localhost, if I set NEXTAUTH_URL_INTERNAL=https://127.0.0.1:3000
then node errors with request to https://127.0.0.1:3000/api/auth/session failed, reason: Hostname/IP does not match certificate's altnames: IP: 127.0.0.1 is not in the cert's list:
. Maybe I could add localhost to the altnames? Or maybe even the server's IP?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我最终通过在单独的端口上运行另一台HTTPS服务器(对于同一应用程序),并带有本地主机的自签名证书来修复它。然后,我将
nextAuth_url_internal
设置为在该端口上查询本地主机。我还必须使用 mkcert 创建自己的ca。默认情况下,Node's Fetth无法识别我的自定义CA,因此我添加了node_extra_ca_certs =“/path/to/path/to/rootca.pem
to/etc/etc/etconiver
。下一个施以通过HTTPS查询Localhost并验证证书(即使是自签名)。
I ended up fixing it by running another HTTPS server (for the same next app) on a separate port with a self-signed certificate for localhost. I then set
NEXTAUTH_URL_INTERNAL
to query localhost on that port. I also had to use mkcert to create my own CA. By default, node's fetch doesn't recognize my custom CA so I addedNODE_EXTRA_CA_CERTS="/path/to/rootCA.pem
to/etc/environment
.All of this allowed next-auth to query localhost over HTTPS and validate the certificate (even though it's self-signed).