Express.js : 원격 클라이언트 주소를 얻는 방법


256

원격 사용자 IP 주소를 얻는 방법을 완전히 이해하지 못합니다.

다음과 같은 간단한 요청 경로가 있다고 가정 해 보겠습니다.

app.get(/, function (req, res){
   var forwardedIpsStr = req.header('x-forwarded-for');
   var IP = '';

   if (forwardedIpsStr) {
      IP = forwardedIps = forwardedIpsStr.split(',')[0];  
   }
});

실제 사용자의 IP 주소를 얻기 위해 위의 방법이 올바른가요? 아니면 더 나은 방법이 있습니까? 프록시는 어떻습니까?


1
here 설명에 따라 node-ipware 를 사용하는 방법은 무엇입니까 ?
un33k

'example.com'과 같은 req.hostname을 얻을 수없는 경우 : stackoverflow.com/a/37824880/5333284
zhi.yang

답변:


469

NGiNX와 같은 프록시 뒤에서 실행 중이거나 가지고있는 것이 있다면 'x-forwarded-for'를 확인해야합니다.

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

프록시가 '귀하의 것'이 아닌 경우 'x-forwarded-for'헤더를 스푸핑 할 수 있기 때문에 신뢰하지 않습니다.


2
이것은 정확하지만 내 상황에서 대괄호를 사용해야했습니다 (위의 편집 참조) 또한 nginx 구성에서 x 전달을 활성화했는지 확인하십시오. 매력처럼 작동합니다!
ninehundreds

43
proxy_set_header X-Forwarded-For $remote_addr;자신의 리버스 프록시를 사용하는 경우이 지시문 을 nginx 구성에 넣어야합니다 .
Coxer

당신이 브라우저에서 HTTP를 (들)이 IP를 사용하려는 경우 : // [IPv6은] : 포트는 공지 사항이 도움이 되었으면 좋겠는 [] 필요를
psuhas

43
copy-pasta 사용자 참고 사항 : 쉼표로 구분 된 IP 주소 목록을 반환 할 수 있습니다. 우리는 이것을 복사하여 결과를 IP와 비교하는 개발자의 버그가있었습니다. 아마도 var ip = (req.headers['x-forwarded-for'] || req.connection.remoteAddress || '').split(',')[0].trim();클라이언트 IP를 얻는 것과 같은 일 을 할 것 입니다.
Davy Jones

3
@Rishav :: 1은 localhost의 IPv6 주소입니다.
Daniel O

238

@alessioalex의 답변이 효과가 있지만 Express-guide프록시 뒤에 표현 섹션에 명시된 다른 방법이 있습니다.

  1. app.set('trust proxy', true)빠른 초기화 코드에 추가하십시오 .
  2. 원격 클라이언트의 IP를 얻으려면 req.ip또는 req.ips일반적인 방법으로 사용하십시오 (역 프록시가없는 것처럼)

선택적인 독서 :

  • req.ip또는을 사용하십시오 req.ips. req.connection.remoteAddress이 솔루션에서는 작동하지 않습니다.
  • 헤더로 'trust proxy'전달 된 모든 것을 신뢰하는 것보다 더 정교한 것을 필요로하는 경우 더 많은 옵션을 사용할 수 있습니다 x-forwarded-for(예 : 프록시가 신뢰할 수없는 소스에서 기존 x-forwarded-for 헤더를 제거하지 않는 경우). 자세한 내용은 링크 된 가이드를 참조하십시오.
  • 프록시 서버가 x-forwarded-for헤더를 채우지 않으면 두 가지 가능성이 있습니다.
    1. 프록시 서버는 원래 요청 위치에 대한 정보를 릴레이하지 않습니다. 이 경우 요청의 원래 위치를 알 수있는 방법이 없습니다. 먼저 프록시 서버의 구성을 수정해야합니다.
      • 예를 들어, nginx를 리버스 프록시로 사용하는 경우 proxy_set_header X-Forwarded-For $remote_addr;구성 에 추가 해야합니다.
    2. 프록시 서버는 요청이 원래 있던 위치에 대한 정보 (예 : 사용자 정의 http 헤더)를 릴레이합니다. 이 경우이 답변이 작동하지 않습니다. 해당 정보를 가져 오는 사용자 정의 방법이있을 수 있지만 먼저 메커니즘을 이해해야합니다.

4
내 대답은 더 일반적이었습니다 (Express와 관련이 없음). Express를 사용하는 경우 실제로 더 나은 방법입니다.
alessioalex

4
프록시 서버에는 'x-forwarded-for'헤더가 원격 주소로 설정되어 있어야합니다. 예를 들어 nginx의 경우 구성 파일에 proxy_set_header X-Forwarded-For $ remote_addr이
있어야

1
IISnode를 프록시 app.enable('trust proxy')로 사용하는 IIS 뒤에는 너무 작동합니다 req.ip. 내가 포트를 얻는 것을 제외하고 1.2.3.4:56789. 그것을 제거하기 위해, 나는 할var ip = req.ip.split(':')[0]
크리스티안 Westerbeek

이 솔루션은 안전합니까?
Daniel Kmak

3
이 답변에는 보안이 부족하고 업데이트가 필요하다고 생각합니다. 항상 응용 프로그램이 신뢰하는 프록시를 정의해야합니다. 수락 된 답변은 적어도 스푸핑에 대해 약간의 통지를합니다. 즉, express를 사용하는 경우 이와 같은 라이브러리를 사용하는 것이 더 나은 솔루션이지만 인용 된 코드가 잘못되어 연결된 리소스에서 찾을 수 없습니다.
Phil

54

에서 nginx.conf파일 :
proxy_set_header X-Real-IP $remote_addr;

에서 node.js서버 파일 :
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;

소문자 헤더를 표현합니다.


3
스택 오버플로에 오신 것을 환영합니다! 코드 블록 만 게시하는 대신이 코드로 인해 문제가 해결되는 이유를 설명하십시오. 설명이 없으면 대답이 아닙니다.
Artemix

1
@ququzone의 대답은 괜찮습니다. 설명은 방문자의 원래 IP 주소를 가져 오는 "x-real-ip"라는 요청에 사용자 정의 헤더를 설정합니다. node 및 socket.io와 함께 작동합니다.
coffekid

8
나를 위해 IP 주소는 대문자로 req.headers['x-real-ip']nginx.conf헤더에 사용 가능 합니다.
Nik Sumeiko

이것이 나를 위해 해결 한 것입니다. trust-proxy가 true로 설정되어 있어도 여전히 로컬 127.0.0.1 주소를 사용하고있었습니다
David

30

특히 노드의 경우 이벤트 연결 에서 http 서버 구성 요소에 대한 설명서 는 다음 같이 말합니다.

새 TCP 스트림이 설정되면 [트리거 됨]. [The] socket은 net.Socket 유형의 객체입니다. 일반적으로 사용자는이 이벤트에 액세스하고 싶지 않습니다. 특히, 소켓은 프로토콜 파서가 소켓에 연결하는 방식 때문에 읽을 수있는 이벤트를 생성하지 않습니다. 소켓은에서 액세스 할 수도 있습니다 request.connection.

따라서 request.connection이는 소켓 임을 의미 하며 설명서 에 따르면 문서에 따라 socket.remoteAddress 속성이 있습니다.

원격 IP 주소의 문자열 표현 예를 들어, '74 .125.127.100 '또는'2001 : 4860 : a005 :: 68 '입니다.

명시 적으로 요청 객체는 Node http 요청 객체의 인스턴스이기도 하므로이 방법은 여전히 ​​작동합니다.

그러나 Express.js에서는 요청에 req.ipreq.ips 라는 두 가지 속성이 이미 있습니다.

req.ip

원격 주소를 반환하거나 "신뢰 프록시"가 활성화 된 경우 업스트림 주소를 반환합니다.

req.ips

"신뢰 프록시는" 이다 true는 "X가 전달 된-은"IP 주소 목록을 구문 분석하고 배열, 그렇지 않은 경우는 하늘의 배열이 반환을 반환합니다. 예를 들어 값이 "client, proxy1, proxy2"인 경우 배열 ""client ","proxy1 ","proxy2 "]를 수신합니다. 여기서"proxy2 "는 가장 다운 스트림입니다.

그것은 가치가 언급 될 수있다, 내 이해에 따르면, Express는 req.ip보다 더 나은 접근 방식 req.connection.remoteAddress때문에,req.ip 실제 클라이언트 ip (신뢰할 수있는 프록시가 명시 적으로 활성화되어있는 경우)를 포함하고 다른 하나는 프록시의 IP 주소를 포함 할 수 가 있습니다. 하나).

이것이 현재 받아 들여진 대답이 제안하는 이유입니다.

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

req.headers['x-forwarded-for']표현에 해당 될 것입니다 req.ip.



7

이것은 이 답변에 대한 추가 정보 일뿐 입니다.

당신이 사용하는 경우 nginxproxy_set_header X-Real-IP $remote_addr; 사이트의 위치 블록에 추가 합니다. /etc/nginx/sites-available/www.example.com예를 들어. 다음은 예제 서버 블록입니다.

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    location / {
        proxy_set_header  X-Real-IP  $remote_addr;
        proxy_pass http://127.0.1.1:3080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

다시 시작한 후에 nginxnode/ express응용 프로그램 경로 에서 IP에 액세스 할 수 있습니다.req.headers['x-real-ip'] || req.connection.remoteAddress;


3

에 따르면 프록시 뒤에 익스프레스 , req.ip사용자가 설정 한 경우 계정 역방향 프록시에 취한 trust proxy제대로. 따라서 req.connection.remoteAddress네트워크 계층에서 얻거나 프록시를 인식하지 못하는 것보다 낫습니다 .


3

그 목적으로 패키지를 작성했습니다. Express 미들웨어로 사용할 수 있습니다. 내 패키지는 여기에 게시됩니다 : https://www.npmjs.com/package/express-ip

다음을 사용하여 모듈을 설치할 수 있습니다

npm i express-ip

용법

const express = require('express');
const app = express();
const expressip = require('express-ip');
app.use(expressip().getIpInfoMiddleware);

app.get('/', function (req, res) {
    console.log(req.ipInfo);
});

1
당신은 포스트에서 제휴를 공개해야 당신이 제휴하고 뭔가에 연결할 때. 제휴를 공개하지 않으면 스팸으로 간주됩니다. 공개는 명시 적이어야하지만 공식적 일 필요는 없습니다 (예 : 자신의 개인 컨텐츠 : "내 사이트 ...", "내 블로그 ..."등). 참조 : "좋은"자기 홍보를 의미한다 무엇? , 자체 프로모션에 대한 몇 가지 팁과 조언 , 스택 오버플로에 대한 "스팸"의 정확한 정의는 무엇입니까? , 무엇을 스팸으로 만드는가 .
Makyen

2

나는이 질문에 대한 답을 알고 있지만, 내가 일을하는 방법은 다음과 같습니다.

let ip = req.connection.remoteAddress.split(`:`).pop();

2

타사 라이브러리를 사용하는 것이 좋습니다. request-ip를 확인할 수 있습니다 .

당신은 그것을 사용할 수 있습니다

import requestIp from 'request-ip';

app.use(requestIp.mw())

app.use((req, res) => {
  const ip = req.clientIp;
});

소스 코드는 꽤 길기 때문에 여기서 복사하지 않습니다. https://github.com/pbojinov/request-ip/blob/master/src/index.js

원래,

요청에서 특정 헤더를 찾고 존재하지 않는 경우 일부 기본값으로 돌아갑니다.

사용자 ip는 다음 순서로 결정됩니다.

  1. X-Client-IP
  2. X-Forwarded-For (헤더는 "클라이언트 IP, 프록시 1 IP, 프록시 2 IP"형식으로 여러 IP 주소를 반환 할 수 있으므로 첫 번째 주소를 사용합니다.)
  3. CF-Connecting-IP (구름 플레어)
  4. Fastly-Client-Ip (클라우드 기능으로 인식 될 때 빠른 CDN 및 Firebase 호스팅 헤더)
  5. True-Client-Ip (Akamai 및 Cloudflare)
  6. X-Real-IP (Nginx 프록시 / FastCGI)
  7. X-Cluster-Client-IP (랙 스페이스 LB, 리버베드 가오리)
  8. X-Forwarded, Forwarded-ForForwarded(2 변형)
  9. req.connection.remoteAddress
  10. req.socket.remoteAddress
  11. req.connection.socket.remoteAddress
  12. req.info.remoteAddress

IP 주소를 찾을 수 없으면를 반환 null합니다.

공개 : 나는 도서관과 관련이 없습니다.


1

이것은 나보다 잘 작동했습니다. 내 사이트는 CloudFlare 뒤에 있으며 필요한 것 같습니다 cf-connecting-ip.

req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress

이 헤더 에 대해 아무 말도하지 않았기 때문에 프록시 뒤에서 Express를 테스트 하지 않았습니다 cf-connecting-ip.


1

can-flare, nginx 및 x-real-ip 지원

var user_ip;

    if(req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
      let first = req.headers['cf-connecting-ip'].split(', ');
      user_ip = first[0];
    } else {
      let user_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }

1

필자의 경우이 솔루션 과 유사하게 다음 x-forwarded-for 접근법을 사용했습니다.

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

x-forwarded-for헤더는 원본에서 최종 대상 서버까지 IP 경로를 계속 추가하므로 원본 클라이언트의 IP를 검색해야하는 경우 이는 배열 의 첫 번째 항목 입니다.


0

var ip = req.connection.remoteAddress;

ip = ip.split ( ':') [3];


출력은 다음과 같습니다 :-:: ffff : XXX.XX.XX.XX 이것에서 우리는 ip를 얻을 것입니다
Bhulawat Ajay

3
ip = ip.split(':').pop();정상적인 IP, 즉 127.0.0.1이 올 경우이 경우 타자가 될 것이라고 생각 합니다. 여전히 IP를 줄 수 있습니다.
9me


0

witk @kakopappa 솔루션과 morgan클라이언트 IP 주소의 로깅을 모두 합치기 :

morgan.token('client_ip', function getId(req) {
    return req.client_ip
});
const LOG_OUT = ':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" :client_ip'
self.app.use(morgan(LOG_OUT, {
    skip: function(req, res) { // custom logging: filter status codes
        return res.statusCode < self._options.logging.statusCode;
    }
}));

// could-flare, nginx and x-real-ip support
var getIpInfoMiddleware = function(req, res, next) {
    var client_ip;
    if (req.headers['cf-connecting-ip'] && req.headers['cf-connecting-ip'].split(', ').length) {
        var first = req.headers['cf-connecting-ip'].split(', ');
        client_ip = first[0];
    } else {
        client_ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
    }
    req.client_ip = client_ip;
    next();
};
self.app.use(getIpInfoMiddleware);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.