κΈ€ λͺ©λ‘μœΌλ‘œ

λ°±μ—”λ“œμ—μ„œ ν΄λΌμ΄μ–ΈνŠΈμ˜ IPλ₯Ό λ‘œκΉ…ν•˜λŠ” 방법

2023. 02. 24.

⚠️ λ’€λ‘œλŠ” 재미있긴 ν•˜λ‚˜ μ •λ¦¬λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. tl;dr ⚠️결둠

μ•„λ§ˆλ„ μ—¬λŸ¬λΆ„λ“€μ€ 직접 λ§Œλ“  λ°±μ—”λ“œκ°€ ν•˜λ‚˜ 쯀은 μžˆμ„κ±°λ‹€.
λ‚˜μ˜ κ²½μš°μ—λŠ” api.tmpf.me 이 μžˆμ—ˆλŠ”λ° ν•œκ°€μ§€ μ•„μ‰¬μš΄ 점이 μžˆμ—ˆλ‹€.

λ°”λ‘œ user access logging.., μ ‘μ†ν•˜λŠ” μœ μ €λ“€μ˜ 기둝을 λ‚¨κΈ°λŠ” μž‘μ—…μ΄ λΆ€μ‘±ν–ˆλ‹€.
사싀 κΌ­ ν•„μš”ν•˜μ§€ μ•Šμ„ μˆ˜λ„ μžˆλŠ”λ° 뭐 ν•„μš”ν•˜λ‹€κ³  μƒκ°ν•˜λ©΄μ„œ 글을 μ½μ–΄λ³΄μž.

μš°μ„  μ—¬λŸ¬κ°€μ§€ 인프라 ꡬ성이 μžˆμ„ 수 μžˆλ‹€.
κ·Έ μ€‘μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„κ°€ λ°”λ‘œ ν†΅μ‹ ν•˜λŠ” 경우

맀우 κ°„λ‹¨ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆλ‹€.
λ°”λ‘œ RemoteAddr ν•„λ“œλ₯Ό νŒŒμ‹±ν•΄μ„œ μ‚¬μš©ν•˜λ©΄ λœλ‹€.

μ•„λž˜ 이미지에 λ³΄μ΄λŠ” κ²ƒμ²˜λŸΌ 211.104.53.76 이 λ°”λ‘œ ν΄λΌμ΄μ–ΈνŠΈμ˜ IP이닀.
(글을 μž‘μ„±ν•˜κ³  μžˆλŠ” λ‚΄ IP) μŠ€νƒ€λ²…μŠ€ 아이피닀.. κ΄΄λ‘­νžˆμ§€ 말자.

λ‘λ²ˆμ§Έ κ²½μš°λ‹€.
μ„œλ²„μ™€ 쀑간에 ν”„λ‘μ‹œ μ„œλ²„κ°€ μ‘΄μž¬ν•˜λŠ” κ²½μš°μ΄λ‹€.
이 κ²½μš°μ—λŠ” μƒˆλ‘­κ²Œ μ•Œμ•„μ•Όλ˜λŠ” 것이 μžˆλŠ”λ° X-Forwarded-For 헀더이닀.

ν•΄λ‹Ή ν—€λ”λŠ” ν”„λ‘μ‹œλ₯Ό μ§€λ‚ λ•Œ μœ μ‹€λ˜λŠ” RemoteAddrλ₯Ό ν”„λ‘μ‹œ 뒀에 μ„œλΉ„μŠ€κΉŒμ§€ μ „λ‹¬ν•˜κΈ° μœ„ν•΄ λ§Œλ“  μ‚¬μ‹€μƒμ˜ ν‘œμ€€ 헀더이닀.
λ‹€μŒ μŠ€ν¬λ¦°μƒ·μ€ whoami μ„œλΉ„μŠ€κ°€ 2개의 λ¦¬λ²„μŠ€ ν”„λ‘μ‹œ λ’€μ—μ„œ μ‹€ν–‰λ˜κ³  μžˆλŠ” κ²½μš°μ΄λ‹€.

μžμ„Ένžˆλ³΄λ©΄ 원본 ν΄λΌμ΄μ–ΈνŠΈ IPλ₯Ό 넣을 수 μžˆλŠ” 뢀뢄이 2κ°€μ§€ μ‘΄μž¬ν•˜λŠ”λ° ν΄λΌμš°λ“œν”Œλ ˆμ–΄μ—μ„œ μΆ”κ°€ν•œ Cf-Connecting-Ip ν•„λ“œμ™€ X-Forwarded-For ν•„λ“œμ˜ 첫번째 값이닀.

μš°μ„  Cf-Connecting-Ip 의 경우 ν΄λΌμš°λ“œν”Œλ ˆμ–΄μ—μ„œ Proxied recordsλ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°μ—λ§Œ ν•΄λ‹Ήλ˜λ―€λ‘œ μ œμ™Έν•˜κ³  μ•„λž˜μ˜ X-Forwarded-For 헀더λ₯Ό μœ μ‹¬νžˆ μ‚΄νŽ΄λ³΄μž.

첫번째 값은 λΆ„λͺ… client ip 이닀. 그럼 λ‹€μŒ 값을 λ¬΄μ—‡μΌκΉŒ?
λ°”λ‘œ ν΄λΌμš°λ“œν”Œλ ˆμ–΄ ν”„λ‘μ‹œ μ„œλ²„μ˜ 아이피이고 κ·Έ λ‹€μŒ μœ„μ—μ„  client ip μ˜€λ˜ RemoteAddr의 경우 ν΄λΌμš°λ“œν”Œλ ˆμ–΄ λ‹€μŒ λ¦¬λ²„μŠ€ν”„λ‘μ‹œμΈ traefik의 아이피이닀.

μœ„μ˜ 이미지와 μ•„μ΄ν”ΌλŠ” λ‹€λ₯΄μ§€λ§Œ λ‹€μŒκ³Ό 같은 ꡬ쑰λ₯Ό μ§€λ‹Œλ‹€.

X-Forwarded-For ν—€λ”λŠ” ν”„λ‘μ‹œλ₯Ό ν•˜λ‚˜ μ§€λ‚ λ•Œ 기쑴의 RemoteAddr 뢀뢄을 X-Forwarded-For 헀더에 appendν•˜κ³  본인인 ν”„λ‘μ‹œ μ„œλ²„μ˜ IPκ°€ RemoteAddr에 λ“€μ–΄κ°€λŠ” ν˜•μ‹μ΄λ‹€.

λ”°λΌμ„œ β€œλŒ€λΆ€λΆ„μ˜ κ²½μš°β€μ— λ‹€μŒ λ‘œμ§μ€ μ •μƒμ μœΌλ‘œ ν΄λΌμ΄μ–ΈνŠΈμ˜ IPλ₯Ό κ°€μ Έμ˜€λŠ”λ° μ„±κ³΅ν•œλ‹€.

forward := r.Header.Get("X-Forwarded-For")
  var ip string
  var err error
  if forward != "" {
    // With proxy
    ip = strings.Split(forward, ",")[0]
  } else {
    // Without proxy
    ip, _, err = net.SplitHostPort(r.RemoteAddr)
    if err != nil {
      http.Error(w, "Error parsing remote address ["+r.RemoteAddr+"]", http.StatusInternalServerError)
      return
    }
  }

근데 μœ„μ— λ‘œμ§μ—λŠ” μ‹¬κ°ν•œ 였λ₯˜κ°€ ν•œκ°€μ§€ μ‘΄μž¬ν•œλ‹€.

λ§Œμ•½ μœ„μ—μ„œ 넣은 IP둜 μ ‘κ·Όμ œμ–΄λ₯Ό ν•œλ‹€κ³  μƒκ°ν•΄λ³΄μž.

μ„œλ²„κ°€ ν”„λ‘μ‹œκ°€ μžˆλŠ” μƒνƒœμ΄λ“  μ—†λŠ” μƒνƒœμ΄λ“  r.HeaderλΌλŠ” 값은 β€œμœ μ €μ—κ²Œμ„œβ€ μ „μ†‘λ˜κ²Œ λ˜μ–΄μžˆλ‹€.

λ˜ν•œ X-Forwarded-For ν—€λ”λŠ” 말 κ·ΈλŒ€λ‘œ HTTP 헀더이닀.

ν—€λ”λŠ” κ°„λ‹¨ν•˜κ²Œ μ‘°μž‘ κ°€λŠ₯ν•˜λ‹€.

λ§Œμ•½ X-Forwarded-For 헀더λ₯Ό 처음 전솑할 λ•Œ β€œμΆ”κ°€β€ ν•œ μƒνƒœλ‘œ μ „μ†‘ν•˜κ²Œ λœλ‹€λ©΄ λ‹€μŒκ³Ό 같은 ν˜•νƒœλ‘œ μ „μ†‘λœλ‹€.

X-Forwarded-For: <λ³€μ‘°ν•˜μ—¬ μΆ”κ°€ν•œ IP A>, <ν΄λΌμ΄μ–ΈνŠΈμ˜ μ‹€μ œ IP B>, <PROXY 1 C>

λ¬Όλ‘  κ²½μš°μ— λ”°λΌμ„œ proxy Cκ°€ 없을 μˆ˜λ„ 있고, ν΄λΌμ΄μ–ΈνŠΈμ˜ μ‹€μ œ IPκ°€ RemoteAddr에 μžˆμ„ μˆ˜λ„ μžˆμ§€λ§Œ 상관 μ—†λ‹€.

μœ„μ— λ…Όλ¦¬λŒ€λ‘œλ©΄ XFF 헀더가 μ„€μ •λ˜μ–΄ μžˆλ‹€. β†’ XFF 헀더 첫번째 값을 μ½λŠ”λ‹€. 이기 λ•Œλ¬Έμ— μœ μ €κ°€ λ³€μ‘°ν•˜μ—¬ μΆ”κ°€ν•œ 값이 μ‹€μ œ IP둜 μΈμ‹λ˜κ²Œ λœλ‹€.

이건 λ¬Έμ œλ‹€.
λ”°λΌμ„œ 이걸 μ²˜λ¦¬ν•  λ³„λ„μ˜ 둜직이 ν•„μš”ν•œλ° …..
λŒ€λΆ€λΆ„μ˜ ν”„λ‘œλ•μ…˜ ν”„λ‘œκ·Έλž¨μ—μ„œ 이 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법을 μ°Ύμ•„λƒˆλ‹€.

μƒˆλ‘œμš΄ μ„€μ • κ°’ FORWORDEDλ₯Ό μƒμ„±ν•œλ‹€.
이 섀정값은 숫자둜 각 μˆ«μžλŠ” λ‹€μŒμ„ λ‚˜νƒ€λ‚Έλ‹€.

숫자의미
0λ¦¬λ²„μŠ€ν”„λ‘μ‹œκ°€ μ—†μœΌλ©° RemoteAddrλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
1μ„œλΉ„μŠ€ μ•žμ— 1개의 λ¦¬λ²„μŠ€ ν”„λ‘μ‹œκ°€ 있으며 XFF ν—€λ”μ˜ -1 번째 값을 μ‚¬μš©ν•©λ‹ˆλ‹€.
....
3μ„œλΉ„μŠ€ μ•žμ— 3개의 λ¦¬λ²„μŠ€ ν”„λ‘μ‹œκ°€ 있으며 XFF ν—€λ”μ˜ -3 번째 값을 μ‚¬μš©ν•©λ‹ˆλ‹€.
4μ„œλΉ„μŠ€ μ•žμ— 4개의 λ¦¬λ²„μŠ€ ν”„λ‘μ‹œκ°€ 있으며 XFF ν—€λ”μ˜ -4 번째 값을 μ‚¬μš©ν•©λ‹ˆλ‹€.
....

μ΄λ ‡κ²Œ ν•œλ‹€λ©΄ λ‹Ήμž₯ μ‚¬μš©μžκ°€ 헀더 값을 λ³€μ‘°ν•˜μ—¬ 보낸 κ²½μš°μ—λ„ 섀정값을 μ΄ˆκ³Όν•˜λŠ” μš”μ²­μ— λŒ€ν•΄μ„œλŠ” κ·Έλƒ₯ λ¬΄μ‹œ ν•˜κΈ°μ— 별 μ˜μ–‘μ„ λ°›μ§€ μ•Šκ²Œ λœλ‹€.

예λ₯Ό λ“€μ–΄ ν΄λΌμš°λ“œ ν”Œλ ˆμ–΄μ™€ traefikλ₯Ό κ±°μ³μ„œ μ„œλΉ„μŠ€λ‘œ νŠΈλ ˆν”½μ΄ λ„μž‘ν•˜λŠ” 경우 FORWORDED ν™˜κ²½λ³€μˆ˜λ₯Ό 2둜 μ„€μ •ν•˜κ³  XFF 헀더 λ°°μ—΄μ—μ„œ -2번째 값을 μ‚¬μš©ν•˜κ²Œ λœλ‹€.
λ”°λΌμ„œ μœ μ €κ°€ μž„μ˜λ‘œ 값을 μΆ”κ°€ν•˜μ—¬λ„ λ¬΄μ‹œλœλ‹€λŠ” μ˜λ―Έμ΄λ‹€.

근데 이 방법은 μ•žμ„œ λ§ν–ˆλ“― μ™„λ²½ν•˜μ§€ μ•Šλ‹€.
μ™œλƒν•˜λ©΄ λ­”κ°€ 섀정값이 μΆ”κ°€λ˜μ—ˆκΈ° λ•Œλ¬Έμ— λͺ¨λ“  ν™˜κ²½μ—μ„œ μ μ‘ν•˜μ—¬ μ„œλΉ„μŠ€ν•˜λŠ” 것이 λΆˆκ°€λŠ₯ν•˜λ‹€.


⚠️ λ’€λ‘œλŠ” 재미있긴 ν•˜λ‚˜ μ •λ¦¬λ˜μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. tl;dr ⚠️

  • FORWORDED ν™˜κ²½ λ³€μˆ˜λŠ” 생각보닀 λ‚˜μ˜μ§€ μ•ŠλŠ” 방식이닀. μΆ”μ²œν•œλ‹€.
  • XFF ν—€λ”μ˜ 아이피 λŒ€μ—­μ„ μ‹ λ’°ν•˜λŠ” ν”„λ‘μ‹œμ˜ λŒ€μ—­μœΌλ‘œ μ„€μ •ν•˜λŠ” 방법도 μžˆλ‹€.
  • XFF ν—€λ”λŠ” μ‘°μž‘μ΄ κ°€λŠ₯ν•˜λ‹ˆ λ―Ώμ§€ 말자.

μ–΄μ©Œλ‹€ λ³΄λ‹ˆ burp suiteλ₯Ό μ΄μš©ν•΄μ„œ λ‚΄κ°€ μ œμž‘ν•œ μ‚¬μ΄νŠΈλ₯Ό κ³΅κ²©ν•˜κ³  μ½”λ“œλ₯Ό λ‹€μ‹œ κ²€μ¦ν•˜κ³  자칫 κ·Έλƒ₯ λ„˜μ–΄κ°ˆ 수 μžˆλŠ” 뢀뢄을 μ κ²€ν•˜κΈ°κΉŒμ§€ ν–ˆλ‹€.

이 λ¬Έμ œλŠ” μ–΄λ–»κ²Œ μ•Œλ €μ Έ μžˆμ„κΉŒ?

λ‹€μŒκ³Ό 같은 μžλ£Œλ“€μ„ 찾을 수 μžˆμ—ˆλŠ”λ° κ·Έ 쀑 ν₯미둜운 λͺ‡κ°€μ§€ μžλ£Œλ‹€.

Untitled

https://blog.ircmaxell.com/2012/11/anatomy-of-attack-how-i-hacked.html

ν•œλ§ˆλ””λ‘œ 글쓴이가 SSH ν„°λ„λ‘œ 인해 우발적으둜 XFF 헀더에 127.0.0.1 μ£Όμ†Œκ°€ λ“€μ–΄κ°€κ²Œ λ˜μ—ˆλŠ”λ° 이λ₯Ό μŠ€νƒμ˜€λ²„ν”Œλ‘œμš°κ°€ β€œκ΄€λ¦¬μžβ€μ˜ μ ‘κ·ΌμœΌλ‘œ 인식해 κΆŒν•œ μƒμŠΉμ΄ μΌμ–΄λ‚¬λ‹€λŠ” 이야기이닀.

또 이런 μžλ£Œλ„ 찾을 수 μžˆμ—ˆλ‹€.

https://www.acunetix.com/vulnerabilities/web/x-forwarded-for-http-header-security-bypass/

XFF HTTP header security bypass, λΆ„λ₯˜λ²ˆν˜Έ CWE-289

CTFd 처럼 ν”„λ‘μ‹œ 홉을 μ œν•œν•˜μ—¬ λ°©μ§€ν•˜λŠ” 둜직이 μžˆλŠ” κ²½μš°λ„ μžˆμ—ˆμ§€λ§Œ 무렀 μŠ€νƒμ˜€λ²„ν”Œλ‘œμš°μ—μ„œ κΆŒν•œ μƒμŠΉμ΄ μΌμ–΄λ‚˜κΈ°λ„ ν•˜λŠ” λ“± μƒλ‹Ήνžˆ μž¬λ°ŒλŠ” κΈ°λ²•μ΄μ˜€λ‹€.

μž¬λ―ΈμžˆμœΌλ‹ˆ 쑰금 더 λ‚˜μ•„κ°€ λ‹€λ₯Έ μ„œλΉ„μŠ€λ“€μ—μ„œ IP λ‘œκΉ… 방법을 κ³΅κ²©ν•˜κ³  λΆ„μ„ν•΄λ³΄μž.

λ¨Όμ € ifconfig.me 이닀.

ν‰μ†Œμ— μ¦κ²¨μ“°λŠ” μ„œλΉ„μŠ€μ΄κΈ°μ— μ„ νƒν•΄λ³΄μ•˜λ‹€.

Untitled

λ‹€μŒκ³Ό 같이 proxy optionλ₯Ό μ„ νƒν•˜μ—¬ interceptλ₯Ό μ§„ν–‰ν–ˆλ‹€.

Untitled

μ•„λ¬΄λŸ° λ³€μ‘°λ₯Ό ν•˜μ§€ μ•Šμ•˜μ„ λ–„ 응닡이닀.

Untitled

μš”μ²­ 헀더에 κ°•μ œλ‘œ 값을 λ„£μ–΄λ³΄μ•˜λ‹€.

Untitled

λΆ„λͺ… 더 값은 μ‘°μž‘λ˜μ—ˆλ‹€.

κ·Έλ ‡λ‹€λ©΄ ifconfig.meλŠ” μ–΄λ–€ λ°©μ‹μœΌλ‘œ client ipλ₯Ό ν™•μΈν• κΉŒ?

githubμ—μ„œ repoλ₯Ό μ°Ύμ•˜λ‹€.

GitHub - pmarques/ifconfig.me: Simple HTTP application for demos and tests

인쀄 μ•Œμ•˜μœΌλ‚˜ λ‹€λ₯Έ μ„œλΉ„μŠ€μ˜€λ‹€λŠ” 이야기..

μ‹€μ œλ‘œ λ‘œμ»¬μ—μ„œ μ‹€ν–‰μ‹œν‚€κ³  β€œμ•„ 이건 μ•„λ‹ˆλ‹€ μ‹Άμ—ˆλ‹€.”

심지어 여기에선 ν•΄λ‹Ή μš°νšŒμ— λŒ€ν•œ λŒ€λΉ„λ₯Ό ν•˜μ§€ μ•Šμ•˜μœΌλ©° 사싀 ν•  ν•„μš”κ°€ μžˆμ§€λŠ”.. κ·Έλƒ₯ λ³΄μ—¬μ£ΌλŠ”κ±°λ‹ˆκΉŒ ~

사싀 이외에도 λ‹€μ–‘ν•œ λž˜ν¬κ°€ β€œA IP echo server inspired byΒ http://ifconfig.me” λΌλŠ” 타이틀 ν•˜μ— μ œμž‘λ˜μ–΄ μžˆμ—ˆλŠ”λ° λͺ‡κ°€μ§€ 래포의 IP νšλ“ λ‘œμ§μ„ κ°€μ Έμ™€λ³΄μ•˜λ‹€.

ip := this.GetString("ip", this.Ctx.Input.IP())

μ—¬κΈ°μ„œ this λ³€μˆ˜λŠ” beego 라이브러리의 λΌμš°ν„° νŒŒλΌλ―Έν„°μ˜€λ‹€.

μž¬λ°ŒλŠ” κ±Έ μ°Ύμ•˜λ‹€.

Security issue: Trusted Reverse Proxy and X-Forwarded-* headers Β· Issue #4589 Β· beego/beego

μ§€κΈˆ λ‚΄κ°€ ν•΄κ²°ν•˜κ³ μž ν•˜λŠ” 문제의 λŒ€ν•œ 이슈인데.. κ·Έλƒ₯ λ‹«ν˜”λ‹€.

μ΄λ ‡λ‹€λŠ”κ±΄ λŒ€λΆ€λΆ„μ˜ beego둜 μž‘μ„±λœ golang λ°±μ—”λ“œ, κ·Έ 쀑 이전에 μ–ΈκΈ‰ν•œ μŠ€νƒμ˜€λ²„ν”Œλ‘œμš°κ°™μ€ λ‘œμ§μ„ μ‚¬μš©ν•˜λŠ” 경우 κ°„λ‹¨ν•˜κ²Œ ν•΄ν‚Ήν•  수 μžˆλ‹€λŠ” 이야기가 λœλ‹€.

// IP returns request client ip.
// if in proxy, return first proxy id.
// if error, return RemoteAddr.
func (input *BeegoInput) IP() string {
	return (*context.BeegoInput)(input).IP()
}

ν˜„μ œ beego의 develop 브랜치의 μ½”λ“œ κ΅¬ν˜„ 및 주석을 λ°œμ΅€ν•΄ μ™”λ‹€.

음.. 2λ²ˆμ— μ£Όμ„μ˜ λœ»μ„ μ§μž‘ν•΄λ³΄λ©΄ β€œμš°λ¦° κ·Έλƒ₯ λ¬΄μ§€μ„±μœΌλ‘œ XXF 더 첫 번째 κ°’ λΊ΄μ˜¬κΊΌμž„ γ……γ„± γ…Žβ€

Untitled

λ‹€μŒμ€ μ € (*context.BeegoInput)(input).IP() κ΅¬ν˜„μ²΄λ‹€.

https://github.com/beego/beego/blob/031c0fc8af57ea1a18e21fd5a7a8e6f23c26bbea/server/web/context/input.go 쀑 μΌλΆ€μ½”λ“œμ΄λ‹€.

// IP returns request client ip.
// if in proxy, return first proxy id.
// if error, return RemoteAddr.
func (input *BeegoInput) IP() string {
	ips := input.Proxy()
	if len(ips) > 0 && ips[0] != "" {
		rip, _, err := net.SplitHostPort(ips[0])
		if err != nil {
			rip = ips[0]
		}
		return rip
	}
	if ip, _, err := net.SplitHostPort(input.Context.Request.RemoteAddr); err == nil {
		return ip
	}
	return input.Context.Request.RemoteAddr
}

이거 λ­”κ°€ κ΅¬ν˜„μ΄ μ΄μƒν•˜λ‹€β€¦

λ§ˆμ§€λ§‰ 희망으둜 input.Proxy() κ΅¬ν˜„μ„ 보자

// Proxy returns proxy client ips slice.
func (input *BeegoInput) Proxy() []string {
	if ips := input.Header("X-Forwarded-For"); ips != "" {
		return strings.Split(ips, ",")
	}
	return []string{}
}

κΉŒμ•½β€¦

이게 λ§žλ‚˜ 싢은 κ΅¬ν˜„μ΄λ‹€.

일단 μ—¬κΈ°κΉŒμ§€ 봀으면 쑰용히 방금 이슈λ₯Ό μ—΄ 수 도 μžˆμ§€λ§Œβ€¦ 일단은 beego λ‚΄λΆ€μ—μ„œ IP() κ΅¬ν˜„μ„ μ–΄λ–»κ²Œ μ‚¬μš©ν•˜λŠ”μ§€ κ²€μƒ‰ν•΄λ³΄μž.

server/web/error.go

"AppError":      fmt.Sprintf("%s:%v", BConfig.AppName, err),
"RequestMethod": ctx.Input.Method(),
"RequestURL":    ctx.Input.URI(),
"RemoteAddr":    ctx.Input.IP(),
"Stack":         stack,
"BeegoVersion":  beego.VERSION,
"GoVersion":     runtime.Version(),

이건 일단 RemoteAddrκ°€ μ•„λ‹ˆλ‹€. 이러면 μ—λŸ¬λ‘œκ·Έλ₯Ό 속일 수 있게 λœλ‹€.

server/web/server.go

record := &logs.AccessLogRecord{
RemoteAddr:     ctx.Input.IP(),
RequestTime:    requestTime,
RequestMethod:  r.Method,
Request:        fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto),

μ—¬κΈ°μ„œλ„ λ§ˆμ°¬κ°€μ§€μ΄λ‹€.

server/web/router.go

if p.cfg.RunMode == DEV && !p.cfg.Log.AccessLogs {
		match := map[bool]string{true: "match", false: "nomatch"}
		devInfo := fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s",
			ctx.Input.IP(),
			logs.ColorByStatus(statusCode), statusCode, logs.ResetColor(),
			timeDur.String(),
			match[findRouter],

μ—¬κΈ°λŠ” dev λͺ¨λ“œμ—μ„œ μ—‘μ„ΈμŠ€λ‘œκΉ…μ„ λ¬Έμ œμžˆλŠ” κ΅¬ν˜„μ²΄λ‘œ ν•˜κ²Œ λœλ‹€.

뭐 beegoμ—μ„œ μ—‘μ„ΈμŠ€λ‘œκΉ…μ„ λ―Ώμ§€ μ•ŠλŠ”κ±Έλ‘œβ€¦

λ‹€μŒμ€ fiber, echoλ₯Ό μ•Œμ•„λ³΄κ² λ‹€.

πŸš€ Trusted Reverse Proxy and get c.Hostname() value from X-Forwarded-Host and etc Β· Issue #1300 Β· gofiber/fiber

λˆ„κ°€ TrustedProxy κΈ°λŠ₯을 μΆ”κ°€ν–ˆλ‹€

IP Address | Echo - High performance, minimalist Go web framework

κ°œλ°œμžκ°€ μ•Œμž˜λ”± 해버렸따.

κ²°λ‘ 

이게 λ‚΄ 결둠이닀.

λ²”μš©μ μœΌλ‘œ 배포할 λ°±μ—”λ“œμ—μ„œ 처음 κ°œλ°œμžκ°€ λ³„λ„μ˜ μ„€μ • 파일 없이 β€œμ‹ λ’°ν•  수 μžˆλŠ”β€ ν΄λΌμ΄μ–ΈνŠΈμ˜ IPλ₯Ό μ–»λŠ”λ‹€λŠ”κ±΄ νž˜λ“€λ‹€.

ν•˜μ§€λ§Œ λͺ‡κ°€μ§€ 선택 κ°€λŠ₯ν•œ μ˜΅μ…˜μ΄ μ‘΄μž¬ν•˜λŠ”λ°

  1. RemoteAddr 만 λ―Ώκ³  λ°±μ—”λ“œλ₯Ό ν”„λ‘μ‹œ 없이 λ°°ν¬ν•˜λŠ” 경우
  2. XFF 헀더 첫번째 값을 μ‚¬μš©ν•˜λ‚˜ μ‹ λ’°ν•  수 μ—†λŠ” μƒνƒœλ‘œ μ‚¬μš©
  3. μ„œλ²„κ°€ 배포될 ν™˜κ²½μ˜ ν”„λ‘μ‹œ 갯수λ₯Ό ν™˜κ²½λ³€μˆ˜λ‘œ μ„€μ •ν•˜μ—¬ μ‹ λ’°ν•  수 μžˆλŠ” ν”„λ‘μ‹œ 갯수λ₯Ό μ„€μ • ν•΄λ‹Ή 갯수 만큼만 XFF 헀더λ₯Ό 읽도둝 μ„€μ •
  4. μ‹ λ’°ν•  수 μžˆλŠ” ν”„λ‘μ‹œμ˜ IP λŒ€μ—­λŒ€λ₯Ό 섀정해두고 κ°€μž₯ κ°€κΉŒμš΄ μ‹ λ’°ν•  수 μ—†λŠ” XFFν—€λ”μ˜ IPλ₯Ό μ‚¬μš©

μ—¬κΈ°μ„œ 3번과 4λ²ˆμ€ μ„€μ • 파일이 ν•„μš”ν•˜λ‚˜ μ„€μ •λ§Œ μž˜ν•œλ‹€λ©΄ μ–Έμ œλ‚˜ μ‹ λ’°ν•  수 μžˆλŠ” IPλ₯Ό κ°€μ§€κ²Œ 되고,

1λ²ˆμ€ μ‹ λ’°λŠ” κ°€λŠ₯ν•˜λ‚˜ ν™˜κ²½μ— 따라 ν΄λΌμ΄μ–ΈνŠΈ IPκ°€ μ•„λ‹Œ κ²½μš°κ°€ (ν”„λ‘μ‹œκ°€ μ‘΄μž¬ν•˜λŠ” 경우) 생길 수 μžˆλ‹€.

2λ²ˆμ€ λ²”μš©μ„±μ€ λ†’μœΌλ‚˜ μ†μ‰½κ²Œ ν•΄ν‚Ήν•  수 μžˆλ‹€.

또 이외에 해결방법도 μ‘΄μž¬ν•œλ‹€.

ν΄λΌμš°λ“œν”Œλ ˆμ–΄λ₯Ό μ‚¬μš©ν•œλ‹€λŠ” κ°€μ •ν•˜μ— Cf-Con… 헀더λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ μ„œλ²„ μ•žλ‹¨μ— μžˆλŠ” ν”„λ‘μ‹œμ—μ„œ X-Real-IP 값을 μ„€μ •ν•˜κ³  κ·Έ κ±Έ μ‹ λ’°ν•˜λŠ” 방법등 λ‹€μ–‘ν•œ 방법이 μžˆλ‹€.

μ–Έμ œλ‚˜ 선택이 ν•„μš”ν•˜κ³  또 λ°±μ—”λ“œ ν”„λ‘œκ·Έλž¨μ„ κ°œλ°œν•  λ•Œλ‚˜ μ‚¬μš©ν•˜κ²Œ λ λ•Œ ν•΄λ‹Ή ν”„λ‘œκ·Έλž¨μ΄ μ–΄λ– ν—₯ κ°œλ°œλ˜μ—ˆλŠ”μ§€ λΆ„μ„ν•˜κ³  μ‹ λ’°ν•  수 μžˆλŠ” 방식인지 κ²€μ¦ν•˜μ—¬μ•Όκ² λ‹€.

κ·Έλž˜μ„œ μ €λŠ” μ–΄λ–»κ²Œ κ°œλ°œν• κ±°λƒλ©΄μš”β€¦

  1. XFF 헀더λ₯Ό μ‚¬μš©
  2. 무쑰건 μ‹ λ’°κ°€ μ•„λ‹Œ λ‘œμ»¬μ£Όμ†Œμ™€ ν΄λΌμš°λ“œν”Œλ ˆμ–΄μ˜ IPλ₯Ό μ‹ λ’°
  3. μΆ”κ°€ ν”„λ‘μ‹œ μ˜΅μ…˜μœΌλ‘œ RemoteAddrλ₯Ό μ‚¬μš©
  4. μΆ”κ°€ μ˜΅μ…˜ μ‹ λ’° κ°€λŠ₯ν•œ ν”„λ‘μ‹œ μ£Όμ†Œλ₯Ό μΆ”κ°€ ν•  수 μžˆλ„λ‘ μ„€μ •
  5. μΆ”κ°€ μ˜΅μ…˜ ν”„λ‘μ‹œ 홉 수둜만 μ„€μ •ν•˜μ—¬ μ‹ λ’°

근데 끝은 μ•„λ‹ˆλ‹€.

κ·Έλž˜λ„ WAFλ‚˜ μ•Œ 수 μ—†λŠ” μ›μΈμœΌλ‘œ 인해 XFF 더가 κ°•μ œ λ³€κ²½λ˜μ–΄ κ³ μ •λ˜κ±°λ‚˜ ν•  μˆ˜λ„ 있기 λ•Œλ¬Έμ— μΌ€λ°”μΌ€λ‹€..

뭐 λ‚΄κ°€ κ°œλ°œν•  λ–„λŠ” μ—΄μ‹¬νžˆ μ°Έκ³ ν•΄μ•Ό


Q. 전에 ν•œλ²ˆ κ΄€μ œ 인프라 점검 λ‹Ήμ‹œ XFF 헀더가 μ‹€μ’…λ˜λŠ” μ΄μƒν•œ 일이 μžˆμ—ˆμ—ˆμ£ ?

κ·Έλ•Œ 원인이 λ­μ˜€λ‚˜μš”?

A. 바보같이 μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜μ„ ν•œλ‹΅μ‹œκ³  μ„€μ •ν•΄λ‘” swarmμ—μ„œ overlay λ„€νŠΈμ›Œν¬ μ„€μ • 덕뢄에 λ„€νŠΈμ›Œν¬κ°€ 이상해진 νƒ“μ΄μ˜€μŠ΅λ‹ˆλ‹€.

ν™•μ‹€νžˆ 순련된 κΈ°μˆ μžκ°€ μ—†μœΌλ©΄ κΈ°μˆ λ„μž…μ„ λ―Έλ€„μ•Όλœλ‹€κ³  λŠλ‚€ λŒ€λͺ©μ΄μ˜€μ£ .

Q. ipLogger ν”„λ‘œμ νŠΈλ₯Ό μ΅œμ’…μ μœΌλ‘œ μ§„ν–‰ν•˜μ…¨λ˜λ°, μ–΄λ–€κ±Έ λŠλΌμ…¨λ‚˜μš”?

A. 생각보닀 λ§Žμ€ ν”„λ‘œμ νŠΈμ—μ„œ XFF 헀더λ₯Ό λ―Ώκ³  μžˆλŠ” 것 κ°™κ³  κ·Έ κ΅¬ν˜„μ΄ λΆˆμ•ˆμ •ν•œ κ²½μš°λ„ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

λ¬Όλ‘  ipLogger ν”„λ‘œμ νŠΈκ°€ μ™„λ²½ν•˜λ‹€λŠ” 것은 μ•„λ‹ˆμ§€λ§Œ μ œμž‘ν•˜λ©° λ‘œκΉ… 기술과 ν΄λΌμ΄μ–ΈνŠΈμ˜ μ§„μ§œ IPλ₯Ό μ–»κ²Œλ˜λŠ” κΈ°μˆ λ©΄μ—μ„œλŠ” ν™•μ‹€νžˆ 곡뢀가 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μž‘μ„±μΌ:2023. 02. 24.
β€’
μˆ˜μ •μΌ:2025. 05. 12.

이전글 / λ‹€μŒκΈ€

← git default branch μ„€μ • λ³€κ²½WSL Arch distro μ„€μ • β†’
Purple Pikmin carrying fruit

written by minpeter β€’ source code

Toggle theme