在使用Firebase云函数将数据保存到Firebase数据库时,我希望同时写入发出请求的IP地址。
然而,req.connection.remoteAddress
总是返回::ffff:0.0.0.0
。是否有一种方法可以获取实际发起请求的客户端的IP地址?
在使用Firebase云函数将数据保存到Firebase数据库时,我希望同时写入发出请求的IP地址。
然而,req.connection.remoteAddress
总是返回::ffff:0.0.0.0
。是否有一种方法可以获取实际发起请求的客户端的IP地址?
客户端的IP地址是request.ip
。
示例:
export const pay = functions.https.onRequest((request, response) => {
console.log(`My IP is ${request.ip}`);
});
functions.https.onCall((data, context) => {...})
)时,context.rawRequest.ip
表示请求的IP地址。 - sceeefunctions.logger.log(context.rawRequest.headers);
查看商品。 - Stefan根据req.headers["x-forwarded-for"]
,该IP地址似乎可用。
请参见:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Forwarded-For
请注意,如果存在代理,则中间的IP地址将被连接到末尾:
X-Forwarded-For: <client_ip>, <proxy_1 : actual-ip-as-seen-by-google> ...
X-Forwarded-For
,并且使用这种方法,他们可以告诉你任何他们想要的IP,而不是真实的IP。 - Brett如果您想通过Firebase Hosting查找客户端IP,则应使用标题fastly-client-ip
,其中将包含真实的客户端IP。
x-forwarded-for
改成了fastly-client-ip
。感谢您发布此更新。 - Robin这适用于我:
const express = require('express');
const logIP = async (req : any, res : any, next : any) => {
const clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.headers['fastly-client-ip'];
}
const logIPApp = express();
logIPApp.use(logIP);
exports.reportIP = functions.https.onRequest(logIPApp);
通常情况下,你可以在X-Forwarded-For
头部的第一个条目中找到真实的客户端IP,但你不能信任它。
当使用Cloud Run(或Cloud Functions gen 2)时,你只能信任最后一个条目(由Cloud Run orchestrator自动添加)。
此外,如果你正在代理Firebase Hosting,我无法找到任何可信任的IP地址的方法。
正如这个回答https://dev59.com/SFYN5IYBdhLWcg3wEEcm#48032910所解释的那样,你可以通过从X-Forwarded-For
头部中取出第一个地址来获取客户端的IP地址。这是一个逗号分隔的地址列表,每个代理都会追加它看到的客户端地址。
然而,请求者可以(恶意地)自行添加X-Forwarded-For
头部,并且每个代理都会追加它。通过这种方式,请求者可以告诉你任何他们想要的IP地址。
如果您正在使用Cloud Run(或Cloud Functions gen 2),那么据我所知,Cloud Run orchestrator始终作为容器的代理。这意味着您可以信任X-Forwarded-For
中的最后一个条目,因为这是Cloud Run本身看到的客户端IP。最后一个地址是您唯一可以信任的地址。列表中的任何前面的地址都可能由请求者或沿途的任何不受信任的代理提供。
如果您将Cloud Run容器(或Cloud Function)代理到Firebase托管后面,则列表中的最后一个地址是Fastly CDN代理,而不是原始客户端地址。您可能会尝试使用倒数第二个地址(或Fastly-Client-IP
标头),但您不能信任此信息。
如果请求者了解您的Cloud Run容器的直接地址(例如<your-service>.a.run.app
),则他们可以直接发出请求,并伪造其中任何一个标头。
您可能会尝试通过检查列表中的最后一个IP地址是信任服务器(似乎Fastly CDN对Cloud Run的请求使用了Google的IP范围之一)来验证请求是否确实来自Fastly/Firebase Hosting CDN,但这并不能排除请求可能来自托管在Fastly或Google Cloud服务上的恶意客户端。
这意味着您不能这样做。您只能信任最后一个地址,因此无法通过Firebase Hosting进行代理。除非GCP/Firebase Hosting团队未来提供一些“可信标头”。
以下是我在使用 Firebase Cloud Functions 时成功的方法:
const clientIP = req.headers['x-appengine-user-ip'] || req.header['x-forwarded-for']
请注意,这在本地无法工作!
之前的答案很有帮助,特别是Brett的长篇解释我非常感激。
如果你在寻找如何在2代onCall云函数中获取客户端IP地址时遇到了这个线程,之前的答案从概念上解释了,但没有给出一个真实的例子。确切的方法是:
exports.exampleFunction = onCall({cors: true}, (request) => {
var index = request.rawRequest.rawHeaders.indexOf('x-forwarded-for');
console.log(request.rawRequest.rawHeaders[index+1]);
});
function getIPFromRequest(request: any) {
return (
request.ip ||
request.headers['fastly-client-ip'] ||
request.headers['x-forwarded-for']?.split(',')[0].trim() ||
request.connection.remoteAddress ||
request.socket.remoteAddress ||
''
);
}
request.ip
来访问客户端的IP地址。原则上,request.ip
实际上是通过获取头部信息来设置的。但是假设request.ip
未设置,我们将自己获取头部信息。简单来说,这就是getIPFromRequest
的作用。const header = ctx.rawRequest.header.bind(ctx.rawRequest)
const ip = (header('x-forwarded-for') || '').split(',')[0]
const ipCountry = header('x-appengine-country') || ''
x-appengine-user-ip
不再起作用,因为它返回的IP地址不是客户端的IP地址(看起来像是服务器或代理的IP地址)。 exports.testUser = async (data, context) => {
console.log('------------------------::context::------------------');
if(context.rawRequest && context.rawRequest.headers){
console.log(context.rawRequest.headers);
}
}
exports.auth = functions.https.onCall(async ({ roomid, userid }, context => {...
- Stefancontext.rawRequest.headers['x-appengine-user-ip']
这种方式吗? - Bhargav Suthar