초기화 함수 init(6)
10418 단어 JavaScriptJavaScript
trust proxy
- express앱 앞에 프록시 서버를 두는경우와 관련되어 있음
- express의 경우 req.ip, req.hostname, req.protocol등을 통하여 클라이언트의 정보를 받아올 수 있음
- 프록시 서버를 설정한 경우 express입장에서는 해당 프록시 서버또한 클라이언트가 됨
- trust proxy를 설정함으로써 프록시 서버의 정보(ip, hostname, protocol)를 가져오는것이 아니라, 실제 클라이언트의 정보를 가져올수 있음
테스트
테스트 조건
- 80포트로 nginx를 동작시키고, 오는 모든 요청을 5000포트로 전달하였다.
brew install nginx
/usr/local/etc/nginx/nginx.conf 설정 파일 변경
brew services start nginx
nginx.conf 설정 파일
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://YOUR_DOMAIN:YOUR_PORT;
}
}
}
https://kirillplatonov.com/2017/11/12/simple_reverse_proxy_on_mac_with_nginx/ 참고
- 5000포트에서 express를 작동시키고 req.ip, req.protocol, req.hostname, req.headers를 확인하였다.
테스트 결과
- trust proxy를 설정하지 않은경우
const express = require("express");
const app = express();
app.get("/", (req, res) => {
console.log(req.ip);
console.log(req.protocol);
console.log(req.hostname);
console.log(req.headers);
res.send("hello");
});
app.listen(5000);
- nginx(80포트)를 통한 접근
::ffff:127.0.0.1 (req.ip)
http (req.protocol)
0.0.0.0 (req.hostname)
{ (req.headers)
host: '0.0.0.0:5000',
connection: 'close',
'upgrade-insecure-requests': '1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1',
'accept-language': 'ko-kr',
'accept-encoding': 'gzip, deflate'
}
- express(5000포트)를 통한 접근
::ffff:192.168.206.153 (req.ip)
http (req.protocol)
192.168.206.141 (req.hostname)
{ (req.headers)
host: '192.168.206.141:5000',
'upgrade-insecure-requests': '1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1',
'accept-language': 'ko-kr',
'accept-encoding': 'gzip, deflate',
connection: 'keep-alive'
}
- trust proxy를 설정한 경우
const express = require("express");
const app = express();
app.set("trust proxy", true);
app.get("/", (req, res) => {
console.log(req.ip);
console.log(req.protocol);
console.log(req.hostname);
console.log(req.headers);
res.send("hello");
});
app.listen(5000);
- nginx(80포트)를 통한 접근
::ffff:127.0.0.1 (req.ip)
http (req.protocol)
0.0.0.0 (req.hostname)
{ (req.headers)
host: '0.0.0.0:5000',
connection: 'close',
'upgrade-insecure-requests': '1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1',
'accept-language': 'ko-kr',
'accept-encoding': 'gzip, deflate'
}
- express(5000포트)를 통한 접근
::ffff:192.168.206.153 (req.ip)
http (req.protocol)
192.168.206.141 (req.hostname)
{ (req.headers)
host: '192.168.206.141:5000',
'upgrade-insecure-requests': '1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1',
'accept-language': 'ko-kr',
'accept-encoding': 'gzip, deflate',
connection: 'keep-alive'
}
문제점
예측
- nginx가 X-Forwarded-For등의 헤더를 통하여 실제 클라이언트의 정보를 전달
- express가 trust proxy설정 여부에 따라 X-Forwarded-For등의 헤더있는 정보를 이용하여 실제 클라이언트의 정보를 설정
실제
- X-Forwarded-For등의 헤더를 nginx가 express에 전달하지 않음
- X-Forwarded-For등의 헤더가 설정되어 있지 않으므로 trust proxy설정은 무의미함
해결
- nginx.conf에 설정 추가
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
- nginx(80포트)를 통한 접근
192.168.206.153 (req.ip)
http (req.protocol)
192.168.206.141 (req.hostname)
{ (req.headers)
'x-real-ip': '192.168.206.153',
'x-forwarded-for': '192.168.206.153',
'x-forwarded-proto': 'http',
'x-forwarded-host': '192.168.206.141',
'x-forwarded-port': '80',
host: '0.0.0.0:5000',
connection: 'close',
'upgrade-insecure-requests': '1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1',
'accept-language': 'ko-kr',
'accept-encoding': 'gzip, deflate'
}
- express(5000포트)를 통한 접근
::ffff:192.168.206.153 (req.ip)
http (req.protocol)
192.168.206.141 (req.hostname)
{ (req.headers)
host: '192.168.206.141:5000',
'upgrade-insecure-requests': '1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Mobile/15E148 Safari/604.1',
'accept-language': 'ko-kr',
'accept-encoding': 'gzip, deflate',
connection: 'keep-alive'
}
- trust proxy를 문자열(ip주소), 숫자(hopcount)등으로도 설정이 가능함
-> app.set("trust proxy", "127.0.0.1");
-> app.set("trust proxy", 0);
테스트를 통하여 배운점
- 검색을 통해 확인한 정보를 검증하였다.
- 실제 어떤식으로 클라이언트의 정보를 가져오는지 확인할 수 있었다.
X-Forwarded-For
- 사실상의 표준 헤더
- HTTP 프록시 또는 로드 밸런서 사용시 실제 클라이언트의 ip주소를 확인하기 위하여 사용한다.
X-Forwarded-For: <client>, <proxy1>, <proxy2>
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For 참고
코드 분석
lib/application
app.defaultConfiguration = function defaultConfiguration() {
var env = process.env.NODE_ENV || "development";
// default settings
this.enable("x-powered-by");
this.set("etag", "weak");
this.set("env", env);
this.set("query parser", "extended");
this.set("subdomain offset", 2);
this.set("trust proxy", false);
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: true,
});
/**
* this.set("trust proxy", false)설정시 @@symbol:trust_proxy_default : false로 설정이 되는데 다시 값을 설정하는 이유
*
* 기본 값이 세팅이 된 경우(app.init()에 의해 설정된 값)와 사용자가 임의로 설정(app.set("trust proxy", true))한 경우를 구분하기 위한것으로 추정됨
*
* 기본 값으로 설정된 경우 @@symbol:trust_proxy_default : true 이며
* 그 이외의 경우에서 "trust proxy"를 설정한 경우
* 굳이 "trust proxy"값을 바꿀때 @@symbol:trust_proxy_default의 값을 바꾸지 않는 한 @@symbol:trust_proxy_default : false가 설정이 됨
*
*/
debug("booting in %s mode", env);
this.on("mount", function onmount(parent) {
// inherit trust proxy
if (
this.settings[trustProxyDefaultSymbol] === true &&
typeof parent.settings["trust proxy fn"] === "function"
) {
delete this.settings["trust proxy"];
delete this.settings["trust proxy fn"];
}
// inherit protos
setPrototypeOf(this.request, parent.request);
setPrototypeOf(this.response, parent.response);
setPrototypeOf(this.engines, parent.engines);
setPrototypeOf(this.settings, parent.settings);
});
// setup locals
this.locals = Object.create(null);
// top-most app is mounted at /
this.mountpath = "/";
// default locals
this.locals.settings = this.settings;
// default configuration
this.set("view", View);
this.set("views", resolve("views"));
this.set("jsonp callback name", "callback");
if (env === "production") {
this.enable("view cache");
}
Object.defineProperty(this, "router", {
get: function () {
throw new Error(
"'app.router' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app."
);
},
});
};
lib/utils/compeilTrust
/**
* val이 true인 경우 항상 true를 리턴하는 함수를 리턴하고
* 숫자인 경우 설정된 hopcount보다 낮은경우 true를 리턴하는 함수를
* 문자열이고 "127.0.0.1, 192.168.0.1"형식의 여러 ip주소가 들어오는 경우
* 문자열을 나눈다.
*/
exports.compileTrust = function (val) {
if (typeof val === "function") return val;
if (val === true) {
// Support plain true/false
return function () {
return true;
};
}
if (typeof val === "number") {
// Support trusting hop count
return function (a, i) {
return i < val;
};
}
if (typeof val === "string") {
// Support comma-separated values
val = val.split(/ *, */);
}
return proxyaddr.compile(val || []);
/**
* val이 undefined, null, false인 경우 빈 배열을 넘기고
* 그 이외의 경우 val을 넘겨준다.
*
* val: undefined || false || null
* -> return () => false;
* 그 이외의 경우 입력돤 ip주소가 val을 통하여 입력된 ip주소와 비교하여 그 결과를 리턴하는 함수를 리턴한다.
*/
};
Author And Source
이 문제에 관하여(초기화 함수 init(6)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dakim/초기화-함수init5-tjjcsrm1저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)