วิธีกำหนดที่อยู่ IP ของผู้ใช้ในโหนด


350

ฉันจะกำหนดที่อยู่ IP ของคำขอที่ได้รับจากภายในคอนโทรลเลอร์ได้อย่างไร ตัวอย่างเช่น (โดยด่วน):

app.post('/get/ip/address', function (req, res) {
    // need access to IP address here
})

23
หากคุณใช้ Express คุณสามารถใช้req.ip source - expressjs.com/en/api.html#req.ip
FrickeFresh


16
สำหรับผู้ที่กำลังทำงานจากlocalhost- เหมือนผมผลสำหรับคำตอบทุกด้านล่าง (เกือบทุกคำตอบที่งาน) ::1อาจจะมา เรื่องนี้ทำให้ฉันสับสนบางครั้ง ภายหลังพบว่า::1เป็นที่อยู่ IP จริงและเป็นIPV6สัญกรณ์สำหรับ localhost Hope this helps someone
Pramesh Bajracharya

คำตอบ:


452

ในrequestวัตถุของคุณมีคุณสมบัติที่เรียกว่าconnectionซึ่งเป็นnet.Socketวัตถุ วัตถุ net.Socket มีคุณสมบัติremoteAddressดังนั้นคุณควรจะได้รับ IP ด้วยการโทรนี้:

request.connection.remoteAddress

ดูเอกสารประกอบสำหรับhttpและnet

แก้ไข

ในฐานะที่เป็น @juand ชี้ให้เห็นในความคิดเห็นวิธีการที่ถูกต้องในการรับ IP ระยะไกลหากเซิร์ฟเวอร์อยู่หลังพร็อกซี request.headers['x-forwarded-for']


6
สิ่งนี้ทำให้ฉันมีที่อยู่ IP แตกต่างจากที่ whatismyip.com ให้ฉัน ทำไมถึงเป็นเช่นนั้น?
Shamoon

3
ฉันมีบริการ API ของฉันติดตั้งอยู่ในอินสแตนซ์no.de เมื่อฉันพยายามเข้าถึงจากคอมพิวเตอร์ของฉันฉันได้รับที่อยู่ IP ของ "10.2.XXX.YYY" ในขณะที่ IP โลกแห่งความจริงของฉันคือ "67.250.AAA.BBB"
Shamoon

7
it request.headers ['X-Forwarded-For']
0x6A75616E

4
โปรดทราบว่า net.Stream ตอนนี้ net.Socket และเอกสารอยู่ที่นี่: nodejs.org/api/net.html#net_class_net_socket
monsur

4
สำหรับใครที่มีความสนใจสำหรับ Heroku มันเป็น: request.headers['x-forwarded-for']
FueledPublishing

408
var ip = req.headers['x-forwarded-for'] || 
     req.connection.remoteAddress || 
     req.socket.remoteAddress ||
     (req.connection.socket ? req.connection.socket.remoteAddress : null);

หมายเหตุว่าบางครั้งคุณจะได้รับมากกว่าหนึ่งที่อยู่ IP req.headers['x-forwarded-for']ใน นอกจากนี้x-forwarded-forส่วนหัวจะไม่ถูกตั้งค่าเสมอซึ่งอาจทำให้เกิดข้อผิดพลาด

รูปแบบทั่วไปของฟิลด์คือ:

X-ส่งสำหรับ: client, proxy1, proxy2, proxy3

โดยที่ค่านั้นเป็นรายการที่อยู่ IP ที่คั่นด้วยเครื่องหมายจุลภาค + เว้นวรรคซ้ายสุดเป็นไคลเอ็นต์ดั้งเดิมและแต่ละพร็อกซีที่ต่อเนื่องที่ผ่านการร้องขอเพิ่มที่อยู่ IP ที่ได้รับการร้องขอ ในตัวอย่างนี้ขอผ่านproxy1, และจากนั้นproxy2 ปรากฏเป็นที่อยู่ระยะไกลของคำขอproxy3proxy3

นี่คือวิธีการแก้ปัญหาที่แนะนำโดยArnav Guptaพร้อมกับการแก้ไขMartinได้แนะนำด้านล่างในความคิดเห็นสำหรับกรณีที่x-forwarded-forไม่ได้ตั้งค่า:

var ip = (req.headers['x-forwarded-for'] || '').split(',').pop().trim() || 
         req.connection.remoteAddress || 
         req.socket.remoteAddress || 
         req.connection.socket.remoteAddress

9
วิธีการป้องกันการปลอมแปลงของส่วนหัวเหล่านี้ว่าอย่างไร
Domi

8
นี้มักจะทำงานได้ดี แต่ด้วยเหตุผลบางอย่างที่ฉันเพิ่งได้ข้อผิดพลาด "ไม่สามารถอ่านคุณสมบัติ 'remoteAddress ของไม่ได้กำหนด" เพราะเห็นได้ชัดว่าทุกอย่างเป็นโมฆะ / req.connection.socketไม่ได้กำหนดรวมทั้ง ฉันไม่แน่ใจว่าทำไม / เงื่อนไขใดเป็นสาเหตุให้เกิดปัญหา แต่ควรตรวจสอบว่าreq.connection.socketมีอยู่เพื่อหลีกเลี่ยงเซิร์ฟเวอร์ของคุณหยุดทำงานหากเกิดกรณีนี้ขึ้น
Matt Browne

9
บรรทัดสุดท้าย req.connection.socket.remote ข้อผิดพลาดในการขว้างปาที่อยู่ ระมัดระวัง.
yAnTar

11
ที่อยู่ ip ที่ส่งคืนคือ :: 1 ทำไม?
Bagusflyer

3
ดูวิธีการทำงานของ pop () ดูเหมือนว่าคุณจะได้รับพร็อกซี่สุดท้ายไม่ใช่ลูกค้าที่เป็นสิ่งที่คุณต้องการ ฉันผิดหรือเปล่า?
มิเชล

86

หากใช้ด่วน ...

req.ip

ฉันมองมันแล้วฉันก็เหมือนรอฉันกำลังใช้ด่วน ดุจ


จะส่งกลับชุดรูปแบบที่ 127.0.0.1 หากเซิร์ฟเวอร์ทำงานอยู่หลังพร็อกซี ใช้Edmar ของคำตอบหรือชุด X-จริง
Dan Dascalescu

31

คุณสามารถเข้าพักแห้งและการใช้งานเพียงโหนด ipwareที่สนับสนุนทั้งIPv4และIPv6

ติดตั้ง:

npm install ipware

ใน app.js หรือมิดเดิลแวร์ของคุณ:

var getIP = require('ipware')().get_ip;
app.use(function(req, res, next) {
    var ipInfo = getIP(req);
    console.log(ipInfo);
    // { clientIp: '127.0.0.1', clientIpRoutable: false }
    next();
});

มันจะพยายามอย่างดีที่สุดในการรับที่อยู่ IP ของผู้ใช้หรือส่งคืน127.0.0.1เพื่อระบุว่าไม่สามารถระบุที่อยู่ IP ของผู้ใช้ได้ ดูไฟล์ READMEเพื่อดูตัวเลือกขั้นสูง


40
"หรือส่งคืน 127.0.0.1 เพื่อระบุว่าไม่สามารถระบุที่อยู่ IP ของผู้ใช้ได้" มีความแตกต่างกันค่อนข้างใหญ่ระหว่าง 127.0.0.1 และไม่ทราบ ...
Nepoxx

4
มันคืนสิ่งที่แปลกสำหรับฉัน:ffff:(not my IP address)เมื่อทดสอบจาก Heroku คำตอบของ @ edmar-miyake ทำงานอย่างถูกต้องสำหรับฉัน
Nilloc

ฉันสงสัยว่า IP จะเป็นอย่างไรถ้าคุณต้องใช้การค้นหา right2left ในกรณี 'x-forwarded-for' var ip_info = get_ip (req, right_most_proxy = True) เช่นเดียวกับในการตั้งค่าบางอย่าง IP ของไคลเอ็นต์อาจเป็น IP ที่เหมาะสมที่สุด
un33k

2
วิธีการนั้นกลับมาclientIp: '::1'สำหรับฉัน ดูเหมือนจะไม่ทำงาน
JamEngulfer

@JamEngulfer - ipware จะทำงานก็ต่อเมื่อที่อยู่ IP ถูกส่งผ่านไปยังแอปของคุณอย่างถูกต้องผ่าน request.headers [] ตัวอย่าง: AWS LBS ส่งที่อยู่ IP ใน 'x-forwarded-for' ในขณะที่ NginX ที่กำหนดเองจำนวนมากใช้ตัวแปรอื่น ๆ ipware พยายามอย่างสุดความสามารถในการหาที่อยู่ IP แต่เฉพาะในกรณีที่ IP ถูกส่งผ่านลงในส่วนหัว
un33k

19

คุณสามารถใช้request-ipเพื่อดึงข้อมูลที่อยู่ IP ของผู้ใช้ มันจัดการกรณีขอบที่แตกต่างกันค่อนข้างน้อยซึ่งบางกรณีถูกกล่าวถึงในคำตอบอื่น ๆ

การเปิดเผย: ฉันสร้างโมดูลนี้

ติดตั้ง:

npm install request-ip

ในแอปของคุณ:

var requestIp = require('request-ip');

// inside middleware handler
var ipMiddleware = function(req, res, next) {
    var clientIp = requestIp.getClientIp(req); // on localhost > 127.0.0.1
    next();
};

หวังว่านี่จะช่วยได้


2
การตรวจสอบซอร์สโค้ดของแพ็คเกจ request-ip ที่github.com/pbojinov/request-ip/blob/master/index.jsตรวจสอบ x-forwarded-for และส่วนหัวอื่น ๆ ทั้งหมดสำหรับ load balancer ยอดนิยมเช่น AWS ELB, Cloudflare , Akamai, nginx, Rackspace LB และปลากระเบนของริเวอร์เบด
จอร์โจ

1
มันกลับมาnullสำหรับฉัน
S.M_Emamian

สิ่งเดียวกันใช้แทนrequest.headers['x-forwarded-for']
Prathamesh

19

request.headers['x-forwarded-for'] || request.connection.remoteAddress

หากมีx-forwarded-forส่วนหัวอยู่ให้ใช้วิธีนั้นมิฉะนั้นให้ใช้.remoteAddressคุณสมบัติ

x-forwarded-forส่วนหัวจะมีการเพิ่มการร้องขอที่ผ่าน balancers โหลด (หรือชนิดอื่น ๆ ของร็อกซี่) การตั้งค่าสำหรับHTTPหรือHTTPS (มันยังเป็นไปได้ที่จะเพิ่มส่วนหัวนี้เพื่อร้องขอเมื่อสมดุลที่TCPระดับโดยใช้โปรโตคอลพร็อกซี่ ) นี่เป็นเพราะrequest.connection.remoteAddressคุณสมบัติจะมีที่อยู่ IP ส่วนตัวของตัวโหลดบาลานซ์แทนที่จะเป็นที่อยู่ IP สาธารณะของลูกค้า โดยใช้หรือคำสั่งในการสั่งซื้อดังกล่าวข้างต้นให้คุณตรวจสอบการดำรงอยู่ของนั้นส่วนหัวและใช้มันถ้ามันมีอยู่อย่างอื่นใช้x-forwarded-forrequest.connection.remoteAddress


12

ฟังก์ชั่นดังต่อไปนี้มีทุกกรณีที่ครอบคลุมจะช่วย

var ip;
if (req.headers['x-forwarded-for']) {
    ip = req.headers['x-forwarded-for'].split(",")[0];
} else if (req.connection && req.connection.remoteAddress) {
    ip = req.connection.remoteAddress;
} else {
    ip = req.ip;
}console.log("client IP is *********************" + ip);

โปรดสังเกตว่า ips นั้นมีค่า, สำหรับฉัน
ThomasReggi

8

การรับที่อยู่ IP มีสองวิธี:

  1. let ip = req.ip

  2. let ip = req.connection.remoteAddress;

แต่มีปัญหากับวิธีการข้างต้น

หากคุณกำลังใช้ app ของคุณหลัง Nginx หรือผู้รับมอบฉันทะใด ๆ ทุกที่อยู่ IP 127.0.0.1เดียวจะ

ดังนั้นทางออกที่ดีที่สุดในการรับที่อยู่ ip ของผู้ใช้คือ: -

let ip = req.header('x-forwarded-for') || req.connection.remoteAddress;

6

หากคุณกำลังใช้รุ่นด่วน 3.x หรือสูงกว่าคุณสามารถใช้การตั้งค่าพร็อกซี่ความไว้วางใจ ( http://expressjs.com/api.html#trust.proxy.options.table ) และมันจะเดินห่วงโซ่ของที่อยู่ใน ส่วนหัว x-forwarded-for และใส่ ip ล่าสุดลงในเชนที่คุณไม่ได้กำหนดค่าเป็นพร็อกซีที่เชื่อถือได้ในคุณสมบัติ ip ของวัตถุ req


6

function getCallerIP(request) {
    var ip = request.headers['x-forwarded-for'] ||
        request.connection.remoteAddress ||
        request.socket.remoteAddress ||
        request.connection.socket.remoteAddress;
    ip = ip.split(',')[0];
    ip = ip.split(':').slice(-1); //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
    return ip;
}


1
คุณถูกต้องถ้าคุณต้องการ ip เป็นสตริงคุณสามารถแทนที่บรรทัดสุดท้ายด้วย: ip = ip.split (':'). slice (-1) [0]
Ahmad Agbaryah

คำตอบแบบรหัสเท่านั้นจะหมดกำลังใจ คุณสามารถอธิบายวิธีการคำตอบนี้จะดีกว่าเก่าดีกว่าอธิบายและ (มาก) upvoted เพิ่มเติมคำตอบ ?
Dan Dascalescu

5

คำเตือน:

อย่าเพิ่งใช้สิ่งนี้เพื่อ จำกัด อัตราสำคัญ:

let ip = request.headers['x-forwarded-for'].split(',')[0];

มันง่ายมากที่จะสวมรอย:

curl --header "X-Forwarded-For: 1.2.3.4" "https://example.com"

ในกรณีนั้นที่อยู่ IP จริงของผู้ใช้จะเป็น:

let ip = request.headers['x-forwarded-for'].split(',')[1];

ฉันประหลาดใจที่ไม่มีคำตอบอื่น ๆ ที่กล่าวถึงนี้


คำตอบด้านบนไม่จัดการนี้โดยpop()ไอเอ็นจีจาก array ซึ่งเป็นทั่วไปมากขึ้นกว่าการองค์ประกอบที่ดัชนี 1 ซึ่งสามารถหลงกลcurl --header "X-Forwarded-For: 1.2.3.4, 5.6.7.8" "https://example.com"โดย
Dan Dascalescu



3

ในโหนด 10.14 ด้านหลัง nginx คุณสามารถดึงข้อมูล ip ได้โดยการร้องขอผ่านส่วนหัวของ nginx ดังนี้:

proxy_set_header X-Real-IP $remote_addr;

จากนั้นในแอปของคุณ:

app.set('trust proxy', true);

หลังจากนั้นทุกที่ที่คุณต้องการให้ปรากฏ:

var userIp = req.header('X-Real-IP') || req.connection.remoteAddress;

2

ฉันรู้ว่าสิ่งนี้ได้รับคำตอบถึงความตาย แต่นี่เป็น ES6 เวอร์ชันใหม่ที่ฉันเขียนซึ่งเป็นไปตามมาตรฐาน eslint ของ airbnb

const getIpAddressFromRequest = (request) => {
  let ipAddr = request.connection.remoteAddress;

  if (request.headers && request.headers['x-forwarded-for']) {
    [ipAddr] = request.headers['x-forwarded-for'].split(',');
  }

  return ipAddr;
};

ส่วนหัว X-Forwarded-For อาจมีรายการ IP พร็อกซีคั่นด้วยเครื่องหมายจุลภาค การสั่งซื้อคือลูกค้า, proxy1, proxy2, ... , proxyN ในโลกแห่งความเป็นจริงผู้คนใช้พร็อกซีที่อาจจัดหาสิ่งที่พวกเขาต้องการในส่วนหัวนี้ หากคุณอยู่เบื้องหลัง load balancer หรืออย่างน้อยคุณสามารถเชื่อถือ IP แรกในรายการได้อย่างน้อยสิ่งที่ proxy ร้องขอมา


1

หากคุณใช้ Graphql-Yoga คุณสามารถใช้ฟังก์ชั่นต่อไปนี้:

const getRequestIpAddress = (request) => {
    const requestIpAddress = request.request.headers['X-Forwarded-For'] || request.request.connection.remoteAddress
    if (!requestIpAddress) return null

    const ipv4 = new RegExp("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")

    const [ipAddress] = requestIpAddress.match(ipv4)

    return ipAddress
}



-7

มีปัญหาเดียวกัน ... ฉันยังใหม่ที่จาวาสคริปต์ แต่ฉันแก้ไขได้ด้วย req.connection.remoteAddress; ที่ให้ที่อยู่ IP ของฉัน (แต่ในรูปแบบ ipv6 :: ffff.192.168.0.101) จากนั้น. sliceเพื่อลบตัวเลข 7 ตัวแรก

var ip = req.connection.remoteAddress;

if (ip.length < 15) 
{   
   ip = ip;
}
else
{
   var nyIP = ip.slice(7);
   ip = nyIP;
}

นี่ไม่ใช่วิธีที่ดีเนื่องจาก ipv6 ไม่ใช่แค่ 7 หลัก + IPv4 แต่อาจแตกต่างกันโดยสิ้นเชิง
Radek

@Radek ถ้าคุณตรวจสอบการเริ่มต้นของที่อยู่มันจะสอดคล้องกับข้อมูลจำเพาะ (ดูen.wikipedia.org/wiki/IPv6_address ctrl-f ค้นหา "IPv4-mapped") ip= (ip.length<15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined))จะแทนที่ if ... ในโค้ดด้านบน
unsynchronized

ฉันเองห่อ getClientIp () จาก npm request-ip เพื่อสร้างfunction getClientIp4(req){ var ip=typeof req==='string'?req:getClientIp(req); return (ip.length<15?ip:(ip.substr(0,7)==='::ffff:'?ip.substr(7):undefined)); }ซึ่งยอมรับ ip ที่ดึงมาก่อนหน้านี้หรือวัตถุคำขอเป็นอินพุตและให้ ip หรือไม่ได้กำหนดเป็นผล
unsynchronized
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.