πŸ™‚

5μž₯. ν΄λΌμ΄μ–ΈνŠΈ μ‚¬μ΄λ“œ μž…λ ₯ 검증

5μž₯. ν΄λΌμ΄μ–ΈνŠΈ μ‚¬μ΄λ“œ μž…λ ₯ 검증
  1. μ€‘μš”μ„±
  1. μž…λ ₯ 검증이 ν•„μš”ν•œ μ£Όμš” λ³΄μ•ˆ μœ„ν˜‘
μ‹€μŠ΅μœ„μ£Ό
λ²¨λ¦¬λ°μ΄μ…˜x
λ³΄μ•ˆλ§Œ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1μž₯. 제λͺ© 1. ν•˜μœ„ 제λͺ© (1) ν•˜μœ„ 제λͺ© 1) ν•˜μœ„ 제λͺ© 1. ν•˜μœ„ 제λͺ© 2. ν•˜μœ„ 제λͺ© 2μž₯. 제λͺ©
 

1. μ€‘μš”μ„±

μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©μžκ°€ μž…λ ₯ν•˜λŠ” λ°μ΄ν„°λŠ” μ‹ λ’°ν•  수 μ—†λŠ” 좜처둜 κ°„μ£Όν•΄μ•Ό ν•œλ‹€. μ‚¬μš©μžκ°€ μ˜λ„μ μœΌλ‘œ μ•…μ„± μ½”λ“œλ₯Ό ν¬ν•¨ν•œ 데이터λ₯Ό μž…λ ₯ν•  수 있기 λ•Œλ¬Έμ—, ν”„λ‘ νŠΈμ—”λ“œ κ°œλ°œμžλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λͺ¨λ“  μž…λ ₯ 값에 λŒ€ν•΄ μ‹ λ’°ν•  수 μžˆλŠ”μ§€μ— λŒ€ν•œ 검증을 μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€.
μž…λ ₯ κ²€μ¦μ˜ λͺ©μ μ€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ˜ˆμƒν•˜μ§€ λͺ»ν•œ μž…λ ₯을 μ²˜λ¦¬ν•˜λŠ” κ³Όμ •μ—μ„œ λ°œμƒν•  수 μžˆλŠ” λ‹€μ–‘ν•œ λ³΄μ•ˆ μœ„ν—˜μ„ λ°©μ§€ν•˜λŠ” 것이닀. μž…λ ₯ 검증은 λ³΄μ•ˆμ μΈ λͺ©μ  외에도 데이터 무결성을 보μž₯ν•˜κ³ , 잘λͺ»λœ λ°μ΄ν„°λ‘œ 인해 λ°œμƒν•  수 μžˆλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 였λ₯˜λ₯Ό μ€„μ΄λŠ” 역할을 ν•œλ‹€.
 
ν”„λ‘ νŠΈμ—”λ“œμ—μ„œ μž…λ ₯ 검증을 μˆ˜ν–‰ν•˜λŠ” μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™λ‹€.
page icon
ν”„λ‘ νŠΈμ—”λ“œμ—μ„œ μž…λ ₯ κ²€μ¦μ˜ μ—­ν• 
  1. λΉ λ₯Έ ν”Όλ“œλ°± 제곡: μ‚¬μš©μžκ°€ 데이터λ₯Ό μž…λ ₯ν•  λ•Œ μ‹€μ‹œκ°„μœΌλ‘œ 였λ₯˜λ₯Ό μ•Œλ €μ£Όμ–΄ λΉ λ₯΄κ²Œ μˆ˜μ •ν•  수 μžˆλ„λ‘ 도와쀀닀.
  1. μ„œλ²„ λ¦¬μ†ŒμŠ€ μ ˆμ•½: 잘λͺ»λœ 데이터가 μ„œλ²„λ‘œ μ „μ†‘λ˜μ§€ μ•Šλ„λ‘ 막아 λΆˆν•„μš”ν•œ μ„œλ²„ μš”μ²­μ„ 쀄이고, μ„œλ²„μ˜ λΆ€ν•˜λ₯Ό 쀄인닀.
  1. λ³΄μ•ˆ 곡격 λ°©μ§€: ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ 기본적인 μž…λ ₯ 검증을 톡해 XSS, SQL μΈμ μ…˜ λ“±μ˜ 곡격 μ‹œλ„λ₯Ό 일차적으둜 차단할 수 μžˆλ‹€.
λ‹€λ§Œ, ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ 검증은 보쑰적인 λ³΄μ•ˆ μ‘°μΉ˜μ— λΆˆκ³Όν•˜λ‹€λŠ” 점을 λͺ…심해야 ν•œλ‹€. κ³΅κ²©μžλŠ” ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μ‹€ν–‰λ˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό λΉ„ν™œμ„±ν™”ν•˜κ±°λ‚˜, ν΄λΌμ΄μ–ΈνŠΈ 검증을 μš°νšŒν•  수 μžˆλŠ” λ‹€μ–‘ν•œ 방법을 μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— λ°˜λ“œμ‹œ μ„œλ²„ μΈ‘μ—μ„œ 좔가적인 검증을 μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€.
 

2. μž…λ ₯ 검증이 ν•„μš”ν•œ μ£Όμš” λ³΄μ•ˆ μœ„ν˜‘

그럼 μ§€κΈˆλΆ€ν„° μž…λ ₯ 검증이 ν•„μš”ν•œ μ£Όμš” λ³΄μ•ˆ μœ„ν˜‘μ— λŒ€ν•΄ μ•Œμ•„λ³΄μž.

(1) XSS λ°©μ§€ (Cross-Site Scripting)

XSS 곡격은 κ³΅κ²©μžκ°€ μ•…μ˜μ μΈ 슀크립트λ₯Ό λ‹€λ₯Έ μ‚¬μš©μžμ˜ λΈŒλΌμš°μ €μ—μ„œ μ‹€ν–‰ν•˜λ„λ‘ ν•˜λŠ” 곡격이닀. ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μ΄λŸ¬ν•œ 곡격을 λ°©μ§€ν•˜λ €λ©΄ μž…λ ₯ 데이터에 HTML νƒœκ·Έλ‚˜ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œκ°€ ν¬ν•¨λ˜μ§€ μ•Šλ„λ‘ 필터링해야 ν•œλ‹€.

1) XSS 취약점이 μžˆλŠ” μ½”λ“œ μ˜ˆμ‹œ

λ‹€μŒμ€ μ‚¬μš©μžκ°€ μž…λ ₯ν•œ 이름을 κ·ΈλŒ€λ‘œ 좜λ ₯ν•˜λŠ” κΈ°λŠ₯이 μžˆλŠ” κ°„λ‹¨ν•œ μ½”λ“œ μ˜ˆμ œμ΄λ‹€. ν•΄λ‹Ή μ½”λ“œμ˜ XSS 취약점과 λ°©μ§€ν•˜λŠ” 법에 λŒ€ν•΄ μ•Œμ•„λ³΄μž.
μ•„λž˜ μ½”λ“œμ—μ„œλŠ” μ‚¬μš©μžκ°€ μž…λ ₯ν•œ 값을 location.searchμ—μ„œ κ°€μ Έμ™€μ„œ document.write() λ©”μ„œλ“œλ₯Ό μ΄μš©ν•΄ νŽ˜μ΄μ§€μ— 좜λ ₯ν•œλ‹€. 이 μ½”λ“œλŠ” μž…λ ₯ 값을 μΈμ½”λ”©ν•˜κ±°λ‚˜ κ²€μ¦ν•˜μ§€ μ•Šκ³  κ·ΈλŒ€λ‘œ HTML에 μ‚½μž…ν•˜κΈ° λ•Œλ¬Έμ—, μ•…μ„± 슀크립트λ₯Ό ν¬ν•¨ν•œ μž…λ ₯ 값이 싀행될 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄ κ³΅κ²©μžκ°€ name νŒŒλΌλ―Έν„°μ— μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μž…λ ₯ν•œλ‹€λ©΄ μ•…μ„± 슀크립트λ₯Ό μ‹€ν–‰μ‹œν‚¬ 수 μžˆλŠ” 것이닀. input[name="name"] μš”μ†Œ
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>XSS Vulnerable Page</title> </head> <body> <h1>Welcome</h1> <form method="GET"> <label for="name">Enter your name:</label> <input type="text" id="name" name="name"> <button type="submit">Submit</button> </form> <div> <h2>Hello, <!-- XSS 취약점이 μžˆλŠ” μ½”λ“œ --> <script> document.write(decodeURIComponent(location.search.split('=')[1])); </script>! </h2> </div> </body> </html>
μœ„ μ½”λ“œμ— λŒ€ν•œ 곡격 μ‹œλ‚˜λ¦¬μ˜€λŠ” μ•„λž˜μ™€ κ°™λ‹€.
page icon
곡격 μ‹œλ‚˜λ¦¬μ˜€
  1. μ‚¬μš©μžκ°€ λ‹€μŒ URL둜 μ ‘μ†ν•œλ‹€κ³  κ°€μ •ν•˜μž:
    1. <http://example.com?name=><script>alert('XSS!');</script>
  1. νŽ˜μ΄μ§€λŠ” μž…λ ₯된 name 값을 κ²€μ¦ν•˜μ§€ μ•Šκ³  κ·ΈλŒ€λ‘œ 좜λ ₯ν•˜λ―€λ‘œ, <script>alert('XSS!');</script> μŠ€ν¬λ¦½νŠΈκ°€ μ‹€ν–‰λœλ‹€.
  1. 결과적으둜, μ‚¬μš©μžμ˜ λΈŒλΌμš°μ €μ—μ„œ alert('XSS!')κ°€ μ‹€ν–‰λ˜λ©°, 이둜 인해 κ³΅κ²©μžκ°€ μ›ν•˜λ©΄ λ”μš± μ•…μ˜μ μΈ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆλ‹€.

2) XSS λ°©μ§€λ₯Ό μœ„ν•œ μ½”λ“œ μˆ˜μ •

XSS 곡격을 λ°©μ§€ν•˜λ €λ©΄ μž…λ ₯ 데이터λ₯Ό κ·ΈλŒ€λ‘œ 좜λ ₯ν•˜μ§€ 말고, HTML μ—”ν‹°ν‹°λ‘œ μΈμ½”λ”©ν•˜κ±°λ‚˜, ν•΄λ‹Ή μž…λ ₯ 값을 검증해야 ν•œλ‹€. HTML μ—”ν‹°ν‹°λ‘œ μΈμ½”λ”©ν•˜λŠ” μˆ˜μ •λœ μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.
<!-- μ€‘λž΅... --> <div> <h2>Hello, <!-- XSS λ°©μ§€λ₯Ό μœ„ν•΄ 데이터λ₯Ό μ•ˆμ „ν•˜κ²Œ 좜λ ₯ --> <script> function sanitizeInput(str) { // μ•…μ„± 슀크립트 차단을 μœ„ν•΄ 특수 문자λ₯Ό HTML μ—”ν‹°ν‹°λ‘œ λ³€ν™˜ // <, >, &, ", ' λ“±μ˜ 특수 λ¬Έμžκ°€ HTMLμ΄λ‚˜ μžλ°”μŠ€ν¬λ¦½νŠΈλ‘œ ν•΄μ„λ˜μ§€ μ•ŠμŒ return str.replace(/&/g, "&amp;") .replace(/</g, "&lt;") .replace(/>/g, "&gt;") .replace(/"/g, "&quot;") .replace(/'/g, "&#039;"); } const params = new URLSearchParams(window.location.search); const name = params.get('name'); if (name) { document.write(sanitizeInput(decodeURIComponent(name))); } </script> </h2> </div> <!-- μ€‘λž΅... -->
이제 μ‚¬μš©μžκ°€ μž…λ ₯ν•œ 값에 μ•…μ„± μŠ€ν¬λ¦½νŠΈκ°€ ν¬ν•¨λ˜μ–΄ μžˆμ–΄λ„, 그것이 μ‹€ν–‰λ˜μ§€ μ•Šκ³  λ‹¨μˆœν•œ ν…μŠ€νŠΈλ‘œ 좜λ ₯λœλ‹€. 예λ₯Ό λ“€μ–΄, κ³΅κ²©μžκ°€ URL에 http://example.com?name=<script>alert('XSS!');</script>λ₯Ό μž…λ ₯ν•˜λ”λΌλ„, νŽ˜μ΄μ§€μ—μ„œλŠ” <script>alert('XSS!');</script>λ₯Ό κ·ΈλŒ€λ‘œ 좜λ ₯ν•  뿐 μ‹€ν–‰ν•˜μ§€ μ•ŠλŠ”λ‹€.

(2) SQL μΈμ μ…˜ λ°©μ§€

ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ SQL μΈμ μ…˜μ΄ μ§μ ‘μ μœΌλ‘œ λ°œμƒν•˜μ§€ μ•Šμ§€λ§Œ, 잘λͺ»λœ μž…λ ₯ 처리λ₯Ό 톡해 μ„œλ²„ μΈ‘μ—μ„œ SQL μΈμ μ…˜μ„ μœ λ°œν•  수 μžˆλ‹€. 즉, ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„λ‘œ μ•…μ„± μž…λ ₯을 μ „μ†‘ν•˜λ©΄, μ„œλ²„κ°€ 이λ₯Ό μ œλŒ€λ‘œ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•΄ SQL μΈμ μ…˜ 곡격을 λ‹Ήν•˜κ²Œ λ˜λŠ” 것이닀. ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ SQL μΈμ μ…˜ 곡격을 λ°©μ§€ν•˜λ €λ©΄ μž…λ ₯ 값을 μ μ ˆν•˜κ²Œ κ²€μ¦ν•˜κ³  ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„ κ°„μ˜ 톡신을 μ•ˆμ „ν•˜κ²Œ μœ μ§€ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€.

1) SQL μΈμ μ…˜ 취약점이 μžˆλŠ” μ½”λ“œ μ˜ˆμ‹œ

λ‹€μŒμ€ κ°„λ‹¨ν•œ HTMLκ³Ό JavaScript μ½”λ“œλ‘œ κ΅¬μ„±λœ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ 폼이닀. 이 μ½”λ“œλŠ” μ‚¬μš©μžμ˜ ID와 λΉ„λ°€λ²ˆν˜Έλ₯Ό μž…λ ₯ λ°›μ•„ μ„œλ²„μ— μ „μ†‘ν•œλ‹€. μ„œλ²„κ°€ 이 μž…λ ₯ 값을 κ²€μ¦ν•˜μ§€ μ•ŠμœΌλ©΄ SQL μΈμ μ…˜ 곡격을 받을 수 μžˆλ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login Page</title> </head> <body> <h1>Login</h1> <form id="loginForm" method="POST" action="login.php"> <label for="username">Username:</label> <input type="text" id="username" name="username"><br> <label for="password">Password:</label> <input type="password" id="password" name="password"><br> <button type="submit">Login</button> </form> </body> </html>
page icon
곡격 μ‹œλ‚˜λ¦¬μ˜€
  1. μ‚¬μš©μžκ°€ username ν•„λ“œμ— 정상적인 IDκ°€ μ•„λ‹Œ SQL μΈμ μ…˜ 곡격 λ¬Έμžμ—΄μ„ μž…λ ₯ν•  수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄, λ‹€μŒκ³Ό 같은 값을 μž…λ ₯ν•  수 μžˆλ‹€.
    1. ' OR 1=1 --
  1. μ„œλ²„κ°€ 이 값을 μ²˜λ¦¬ν•  λ•Œ SQL 쿼리가 λ‹€μŒκ³Ό 같이 μ‘°μž‘λ  수 μžˆλ‹€.
    1. SELECT * FROM users WHERE username = '' OR 1=1 -- ' AND password = 'password';
  1. 이 μΏΌλ¦¬λŠ” 항상 참이 되기 λ•Œλ¬Έμ—, κ³΅κ²©μžλŠ” λΉ„λ°€λ²ˆν˜Έλ₯Ό μž…λ ₯ν•˜μ§€ μ•Šκ³ λ„ λ°μ΄ν„°λ² μ΄μŠ€μ˜ λͺ¨λ“  μ‚¬μš©μžλ₯Ό μ‘°νšŒν•˜κ±°λ‚˜ κ΄€λ¦¬μž κΆŒν•œμ„ 얻을 수 μžˆλ‹€.

2) SQL μΈμ μ…˜μ„ λ°©μ§€ν•  수 있게 μ½”λ“œ μˆ˜μ •

JavaScriptλ₯Ό μ΄μš©ν•΄ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ κ°„λ‹¨ν•œ μž…λ ₯ 검증을 μˆ˜ν–‰ν•  수 μžˆλ‹€. SQL 특수 λ¬Έμžλ‚˜ 비정상적인 μž…λ ₯을 μ°¨λ‹¨ν•˜λŠ” 기본적인 검증을 μ μš©ν•  수 μžˆλ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Login Page</title> <script> // usernameκ³Ό password ν•„λ“œμ—μ„œ SQL μΈμ μ…˜μ— μ‚¬μš©λ  수 μžˆλŠ” 특수 문자λ₯Ό 검사 function validateForm() { const username = document.getElementById('username').value; const password = document.getElementById('password').value; // κ°„λ‹¨ν•œ SQL μΈμ μ…˜ νŒ¨ν„΄ 필터링 //', ", ;, -을 ν¬ν•¨ν•œ λ¬Έμžμ—΄μ΄ μžˆλŠ” 경우, μ‚¬μš©μžμ—κ²Œ κ²½κ³ λ₯Ό ν‘œμ‹œν•˜κ³  폼 μ œμΆœμ„ 쀑단 const sqlInjectionPattern = /['";--]/; if (sqlInjectionPattern.test(username) || sqlInjectionPattern.test(password)) { alert('Invalid characters in input.'); return false; // 폼 제좜 쀑단 } return true; // 폼 제좜 ν—ˆμš© } </script> </head> <body> <!-- μ€‘λž΅... --> </body> </html>
μœ„μ™€ 같이 ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ 검증을 톡해 쿼리에 특수 λ¬Έμžκ°€ ν¬ν•¨λ˜μ§€ μ•Šλ„λ‘ ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ μž…λ ₯ 검증은 우회될 수 있기 λ•Œλ¬Έμ—, μ„œλ²„λŠ” λ°˜λ“œμ‹œ SQL μΈμ μ…˜μ„ λ°©μ–΄ν•΄μ•Ό ν•œλ‹€. SQL μΈμ μ…˜μ€ μ„œλ²„ μΈ‘μ—μ„œ λ°˜λ“œμ‹œ 막아야 ν•˜λ©° ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œλ§Œμ˜ μ‘°μΉ˜λ‘œλŠ” 막을 μˆ˜λŠ” μ—†λ‹€.

(3) CSRF λ°©μ§€ (Cross-Site Request Forgery)

CSRF 곡격은 μ‚¬μš©μžκ°€ μ˜λ„ν•˜μ§€ μ•Šμ€ μš”μ²­μ„ κ°•μ œλ‘œ μ‹€ν–‰ν•˜κ²Œ λ§Œλ“œλŠ” 곡격이닀. 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ CSRF 토큰을 확인할 수 μžˆλ‹€.
*CSRF (Cross-Site Request Forgery)**λŠ” μ›Ήμ‚¬μ΄νŠΈμ—μ„œ μ‚¬μš©μžμ˜ κΆŒν•œμ„ μ΄μš©ν•΄ μ‚¬μš©μžμ˜ μ˜λ„μ™€ 상관없이 μ•…μ˜μ μΈ μš”μ²­μ„ μ„œλ²„λ‘œ λ³΄λ‚΄λŠ” κ³΅κ²©μž…λ‹ˆλ‹€. μ‚¬μš©μžκ°€ μ‚¬μ΄νŠΈμ— λ‘œκ·ΈμΈν•œ μƒνƒœμ—μ„œ κ³΅κ²©μžκ°€ μ€€λΉ„ν•œ μ•…μ„± 슀크립트 λ˜λŠ” 링크λ₯Ό ν΄λ¦­ν•˜λ©΄, μ‚¬μš©μžμ˜ κΆŒν•œμœΌλ‘œ μ„œλ²„μ— μš”μ²­μ΄ μ „μ†‘λ˜μ–΄ μ˜λ„μΉ˜ μ•Šμ€ λ™μž‘(예: κ³„μ’Œ 이체, λΉ„λ°€λ²ˆν˜Έ λ³€κ²½ λ“±)을 μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
κ³΅κ²©μžλŠ” μ‚¬μš©μžμ˜ 인증 정보λ₯Ό μ•…μš©ν•˜μ—¬ ν•΄λ‹Ή μ‚¬μš©μžμ˜ κΆŒν•œμœΌλ‘œ μ„œλ²„μ— μš”μ²­μ„ 보내기 λ•Œλ¬Έμ—, 곡격은 μ‚¬μš©μžκ°€ λ‘œκ·ΈμΈν•œ μƒνƒœμ—μ„œ 더 μœ„ν—˜ν•˜κ²Œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.

1) CSRF 취약점이 μžˆλŠ” μ½”λ“œ μ˜ˆμ‹œ

μ•„λž˜μ˜ κ°„λ‹¨ν•œ μ½”λ“œ μ˜ˆμ‹œλŠ” μ‚¬μš©μžκ°€ λ‘œκ·ΈμΈν•œ μƒνƒœμ—μ„œ λΉ„λ°€λ²ˆν˜Έλ₯Ό λ³€κ²½ν•  수 μžˆλŠ” νŽ˜μ΄μ§€μž…λ‹ˆλ‹€. CSRF λ°©μ–΄ μ‘°μΉ˜κ°€ 없을 경우, κ³΅κ²©μžλŠ” μ‚¬μš©μžμ˜ κΆŒν•œμœΌλ‘œ μ•…μ˜μ μΈ μš”μ²­μ„ 보낼 수 μžˆμŠ΅λ‹ˆλ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Change Password</title> </head> <body> <h1>Change Password</h1> <form id="passwordForm" method="POST" action="change_password.php"> <label for="newPassword">New Password:</label> <input type="password" id="newPassword" name="newPassword"><br> <button type="submit">Change Password</button> </form> </body> </html>
page icon
곡격 μ‹œλ‚˜λ¦¬μ˜€
  1. μ‚¬μš©μžκ°€ 이미 둜그인된 μƒνƒœμ—μ„œ κ³΅κ²©μžκ°€ μ‘°μž‘ν•œ μ•…μ„± νŽ˜μ΄μ§€λ₯Ό λ°©λ¬Έν•œλ‹€.
  1. κ³΅κ²©μžλŠ” λ‹€μŒκ³Ό 같은 URL둜 μ‚¬μš©μžμ˜ κΆŒν•œμ„ μ΄μš©ν•΄ λΉ„λ°€λ²ˆν˜Έ λ³€κ²½ μš”μ²­μ„ μ „μ†‘ν•œλ‹€.
    1. <img src="<http://example.com/change_password.php?newPassword=hacked123>" style="display:none;">
  1. μ‚¬μš©μžκ°€ 이 νŽ˜μ΄μ§€λ₯Ό λ°©λ¬Έν•˜λ©΄ 이미지가 λ‘œλ“œλ˜λ©΄μ„œ http://example.com/change_password.php?newPassword=hacked123둜 μš”μ²­μ΄ μžλ™μœΌλ‘œ μ „μ†‘λœλ‹€. μ„œλ²„λŠ” μ‚¬μš©μžκ°€ μš”μ²­ν•œ κ²ƒμœΌλ‘œ μ°©κ°ν•˜κ³  λΉ„λ°€λ²ˆν˜Έλ₯Ό λ³€κ²½ν•˜κ²Œ λœλ‹€.

1) CSRF λ°©μ§€λ₯Ό μœ„ν•œ μ½”λ“œ μˆ˜μ •

μ„œλ²„μ—μ„œ μƒμ„±λœ CSRF 토큰을 폼에 μΆ”κ°€ν•˜μ—¬ ν΄λΌμ΄μ–ΈνŠΈκ°€ μš”μ²­μ„ 보낼 λ•Œλ§ˆλ‹€ μ„œλ²„λŠ” 이 토큰을 κ²€μ¦ν•œλ‹€. CSRF 토큰은 μ„Έμ…˜λ§ˆλ‹€ κ³ μœ ν•˜λ©°, 이λ₯Ό 톡해 μ•…μ„± μ‚¬μ΄νŠΈμ—μ„œλŠ” μ μ ˆν•œ 토큰을 ν¬ν•¨ν•œ μš”μ²­μ„ 보낼 수 μ—†κ²Œ λœλ‹€.
<!-- μ€‘λž΅.. --> <!-- CSRF 토큰을 폼에 μΆ”κ°€ --> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> <!-- μ€‘λž΅.. -->
μœ„μ™€ 같이 ν΄λΌμ΄μ–ΈνŠΈκ°€ μ œμΆœν•˜λŠ” λͺ¨λ“  νΌμ—λŠ” CSRF 토큰이 ν¬ν•¨λ˜μ–΄μ•Ό ν•œλ‹€. 이 토큰은 μ„œλ²„μ—μ„œ μƒμ„±λœ 토큰과 μΌμΉ˜ν•΄μ•Ό ν•˜λ―€λ‘œ, κ³΅κ²©μžκ°€ μž„μ˜λ‘œ μ‘°μž‘ν•œ μš”μ²­μ€ 토큰이 μΌμΉ˜ν•˜μ§€ μ•Šμ„ κ²ƒμ΄λ―€λ‘œ μ‹€νŒ¨ν•˜κ²Œ λœλ‹€.
 

(4) 파일 μ—…λ‘œλ“œ 검증

μ‚¬μš©μžκ°€ νŠΉμ • νŒŒμΌμ„ μ—…λ‘œλ“œν•˜λ €κ³  ν•œλ‹€κ³  κ°€μ •ν•΄ 보자. λ§Œμ•½ μ‚¬μš©μžκ°€ μ—…λ‘œλ“œν•œ 파일이 μ„œλ²„μ—μ„œ μš”κ΅¬ν•˜λŠ” 파일 ν˜•μ‹μ΄ μ•„λ‹ˆλΌλ©΄ μ–΄λ–€ λ¬Έμ œκ°€ μΌμ–΄λ‚ κΉŒ? 예λ₯Ό λ“€μ–΄ .exe λ‚˜ .js 와 같은 포맷의 μ•…μ„± 파일일 경우, λ³΄μ•ˆ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆλ‹€. λ”°λΌμ„œ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œλŠ” 파일의 ν˜•μ‹μ΄ μ μ ˆν•œμ§€, μ•ˆμ „ν•œμ§€ μ—¬λΆ€λ₯Ό λ°˜λ“œμ‹œ 확인해야 ν•œλ‹€.

1) 파일 μ—…λ‘œλ“œ 검증이 μ—†λŠ” μ·¨μ•½ν•œ μ½”λ“œ

μ•„λž˜λŠ” 파일 μ—…λ‘œλ“œλ₯Ό μ²˜λ¦¬ν•˜λŠ” κ°„λ‹¨ν•œ HTML 폼과 JavaScript μ½”λ“œμ΄λ‹€. ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 파일 μœ ν˜•μ΄λ‚˜ 크기에 λŒ€ν•œ 검증이 μ—†μœΌλ―€λ‘œ, μ‚¬μš©μžκ°€ μ•…μ„± νŒŒμΌμ„ μ—…λ‘œλ“œν•  수 μžˆλ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload</title> </head> <body> <h1>Upload a File</h1> <form id="uploadForm" method="POST" action="upload.php" enctype="multipart/form-data"> <input type="file" name="file" id="file"><br> <button type="submit">Upload</button> </form> </body> </html>
page icon
곡격 μ‹œλ‚˜λ¦¬μ˜€
  1. κ³΅κ²©μžλŠ” μ•…μ„± μŠ€ν¬λ¦½νŠΈκ°€ ν¬ν•¨λœ .php, .js, .exe λ“±μ˜ νŒŒμΌμ„ μ—…λ‘œλ“œν•  수 μžˆλ‹€.
  1. 예λ₯Ό λ“€μ–΄, shell.php와 같은 νŒŒμΌμ„ μ—…λ‘œλ“œν•˜λ©΄ μ„œλ²„λŠ” 이 νŒŒμΌμ„ μ €μž₯ν•  수 있고, κ³΅κ²©μžλŠ” ν•΄λ‹Ή νŒŒμΌμ— μ ‘κ·Όν•˜μ—¬ μ„œλ²„μ—μ„œ λͺ…령을 μ‹€ν–‰ν•˜κ±°λ‚˜ κΆŒν•œμ„ 얻을 수 μžˆλ‹€.
<?php // μ•…μ„± 파일 μ˜ˆμ‹œ (shell.php) echo "This is a shell"; system($_GET['cmd']); ?>
κ³΅κ²©μžλŠ” 이 νŒŒμΌμ„ μ„œλ²„μ— μ—…λ‘œλ“œν•œ ν›„, URL을 톡해 λͺ…령을 μ‹€ν–‰ν•  수 μžˆλ‹€.
<http://example.com/uploads/shell.php?cmd=ls>
이둜 인해 μ„œλ²„μ—μ„œ μž„μ˜μ˜ λͺ…령이 싀행될 수 있고, μ‹¬κ°ν•œ λ³΄μ•ˆ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆλ‹€.

2) 파일 μ—…λ‘œλ“œ 검증이 μΆ”κ°€λœ μ½”λ“œ μˆ˜μ •

파일 μ—…λ‘œλ“œλŠ” ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„ 간에 데이터λ₯Ό μ£Όκ³ λ°›λŠ” μ€‘μš”ν•œ λΆ€λΆ„ 쀑 ν•˜λ‚˜μ΄λ©°, 이 κ³Όμ •μ—μ„œ μ μ ˆν•œ λ³΄μ•ˆ μ‘°μΉ˜κ°€ μ·¨ν•΄μ§€μ§€ μ•ŠμœΌλ©΄ κ³΅κ²©μžκ°€ μ•…μ„± νŒŒμΌμ„ μ—…λ‘œλ“œν•˜μ—¬ μ„œλ²„μ— μ•…μ˜ν–₯을 끼칠 수 μžˆλ‹€. μ•„λž˜λŠ” 파일 ν™•μž₯μžμ™€ 파일 크기λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 미리 ν™•μΈν•˜κ³ , ν—ˆμš©λ˜μ§€ μ•ŠλŠ” νŒŒμΌμ„ μ—…λ‘œλ“œν•˜μ§€ λͺ»ν•˜λ„둝 ν•˜λŠ” μ½”λ“œμ΄λ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload</title> <script> function validateFile() { const fileInput = document.getElementById('file'); const file = fileInput.files[0]; // ν—ˆμš©λ˜λŠ” 파일 ν™•μž₯자 const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif']; const fileSizeLimit = 2 * 1024 * 1024; // 2MB μ œν•œ const fileExtension = file.name.split('.').pop().toLowerCase(); // 파일 ν™•μž₯자 확인 if (!allowedExtensions.includes(fileExtension)) { alert('Only JPG, JPEG, PNG, and GIF files are allowed.'); return false; } // 파일 크기 확인 if (file.size > fileSizeLimit) { alert('File size must be less than 2MB.'); return false; } return true; } </script> </head> <body> <h1>Upload a File</h1> <form id="uploadForm" method="POST" action="upload.php" enctype="multipart/form-data" onsubmit="return validateFile();"> <input type="file" name="file" id="file"><br> <button type="submit">Upload</button> </form> </body> </html>
ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œλŠ” 파일의 μœ ν˜•κ³Ό 크기, ν™•μž₯자 등을 κ²€μ‚¬ν•˜λŠ” 기본적인 λ³΄μ•ˆ 쑰치λ₯Ό μ μš©ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ 검증은 μ‚¬μš©μž κ²½ν—˜ ν–₯상에 도움이 λ˜μ§€λ§Œ, μ‹ λ’°ν•  수 μ—†λŠ” ν™˜κ²½μ—μ„œλŠ” μ‰½κ²Œ 우회될 수 있기 λ•Œλ¬Έμ— μ„œλ²„ μΈ‘μ—μ„œλ„ λ°˜λ“œμ‹œ 검증을 μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€.
 

(6) μž…λ ₯ 데이터 길이 μ œν•œ

또 λ‹€λ₯Έ 예둜, μ‚¬μš©μžκ°€ λΉ„λ°€λ²ˆν˜Έλ₯Ό μž…λ ₯ν•œλ‹€κ³  κ°€μ •ν•΄ 보자. λ§Œμ•½ μž…λ ₯된 λΉ„λ°€λ²ˆν˜Έκ°€ λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯ν•  수 μžˆλŠ” 길이보닀 κΈΈλ‹€λ©΄, μ„œλ²„μ— 였λ₯˜κ°€ λ°œμƒν•  수 μžˆλ‹€. λ”°λΌμ„œ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μž…λ ₯ λ°μ΄ν„°μ˜ 길이λ₯Ό μ œν•œν•˜μ—¬ 이런 였λ₯˜λ₯Ό μ˜ˆλ°©ν•΄μ•Ό ν•œλ‹€.
ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μž…λ ₯ λ°μ΄ν„°μ˜ 길이λ₯Ό μ œν•œν•˜μ§€ μ•ŠμœΌλ©΄, 버퍼 μ˜€λ²„ν”Œλ‘œμš°(Buffer Overflow)λ‚˜ μ„œλΉ„μŠ€ κ±°λΆ€ 곡격(Denial of Service, DoS) λ“±κ³Ό 같은 λ‹€μ–‘ν•œ 곡격에 λ…ΈμΆœλ  수 μžˆλ‹€. 특히 μ„œλ²„λ‚˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 이 μž…λ ₯을 κ·ΈλŒ€λ‘œ μ²˜λ¦¬ν•  경우, μ„±λŠ₯ μ €ν•˜, 데이터 μœ μ‹€, λ³΄μ•ˆ 취약점 λ°œμƒ λ“±μ˜ λ¬Έμ œκ°€ 생길 수 μžˆλ‹€.

1) μž…λ ₯ 데이터 길이 μ œν•œμ΄ μ—†λŠ” μ·¨μ•½ν•œ μ½”λ“œ μ˜ˆμ‹œ

λ‹€μŒμ€ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μž…λ ₯ 데이터에 λŒ€ν•œ 길이 μ œν•œμ΄ μ—†λŠ” κ°„λ‹¨ν•œ 폼이닀. 이 폼은 μ„œλ²„μ— 데이터 전솑을 ν—ˆμš©ν•˜μ§€λ§Œ, ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μž…λ ₯된 λ°μ΄ν„°μ˜ 길이λ₯Ό μ „ν˜€ κ²€μ¦ν•˜μ§€ μ•ŠλŠ”λ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Simple Form</title> </head> <body> <h1>Submit Your Feedback</h1> <form id="feedbackForm" method="POST" action="submit_feedback.php"> <label for="feedback">Feedback:</label><br> <textarea id="feedback" name="feedback"></textarea><br> <button type="submit">Submit</button> </form> </body> </html>
μœ„ νΌμ—λŠ” 길이 μ œν•œμ΄ μ—†μœΌλ―€λ‘œ μ‚¬μš©μžκ°€ μž„μ˜λ‘œ 길이λ₯Ό μ΄ˆκ³Όν•˜λŠ” 데이터, 심지어 맀우 큰 데이터λ₯Ό μž…λ ₯ν•  수 μžˆλ‹€. 이둜 인해 μ„œλ²„λŠ” λ§Žμ€ 데이터λ₯Ό μ²˜λ¦¬ν•΄μ•Ό ν•˜λ©°, κ³Όλ„ν•œ λ©”λͺ¨λ¦¬ μ‚¬μš©μœΌλ‘œ 인해 μ„œλ²„κ°€ λ‹€μš΄λ˜κ±°λ‚˜ 예기치 μ•Šμ€ λ™μž‘μ„ μœ λ°œν•  수 μžˆλ‹€.
page icon
곡격 μ‹œλ‚˜λ¦¬μ˜€
  • 버퍼 μ˜€λ²„ν”Œλ‘œμš°(Buffer Overflow): ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 맀우 κΈ΄ λ¬Έμžμ—΄μ„ μž…λ ₯ν•˜κ³  μ„œλ²„λ‘œ μ „μ†‘ν•˜λ©΄, μ„œλ²„μ˜ λ©”λͺ¨λ¦¬κ°€ λ„˜μ³ κ³΅κ²©μžκ°€ μ„œλ²„μ— μ•…μ˜μ μΈ μ½”λ“œλ₯Ό μ£Όμž…ν•˜κ±°λ‚˜ 예기치 μ•Šμ€ 행동을 μœ λ„ν•  수 μžˆλ‹€.
  • μ„œλΉ„μŠ€ κ±°λΆ€ 곡격(Denial of Service, DoS): ν΄λΌμ΄μ–ΈνŠΈκ°€ 맀우 큰 데이터λ₯Ό μ—¬λŸ¬ 번 λ³΄λ‚΄λ©΄μ„œ μ„œλ²„μ˜ μžμ›μ„ μ†Œλͺ¨μ‹œν‚€λ©΄, μ„œλ²„μ˜ 응닡 μ‹œκ°„μ΄ λŠλ €μ§€κ±°λ‚˜ μ™„μ „νžˆ 쀑단될 수 μžˆλ‹€.

2) μž…λ ₯ 데이터 길이 μ œν•œν•˜λ„λ‘ μ½”λ“œ μˆ˜μ •

ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ μž…λ ₯ λ°μ΄ν„°μ˜ 길이λ₯Ό μ œν•œν•˜λŠ” 것은 첫 번째 방어선에 ν•΄λ‹Ήν•œλ‹€. ν•˜μ§€λ§Œ 이 검증은 μ‰½κ²Œ 우회될 수 있기 λ•Œλ¬Έμ—, μ„œλ²„ μΈ‘μ—μ„œ λ°˜λ“œμ‹œ 좔가적인 검증이 ν•„μš”ν•˜λ‹€.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Feedback Form</title> <script> function validateInput() { const feedback = document.getElementById('feedback').value; const maxLength = 500; // μ΅œλŒ€ κΈ€μž 수 μ œν•œ if (feedback.length > maxLength) { alert(`Feedback cannot exceed ${maxLength} characters.`); return false; } return true; } </script> </head> <!-- μ€‘λž΅.. -->
 
 
μ§€κΈˆκΉŒμ§€ ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œμ˜ μž…λ ₯ 검증에 λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜λ‹€. ν΄λΌμ΄μ–ΈνŠΈ μ‚¬μ΄λ“œ μž…λ ₯ κ²€μ¦μœΌλ‘œ 기본적인 λ³΄μ•ˆ μœ„ν˜‘μ„ 쀄일 수 μžˆμ§€λ§Œ, μ΄λŠ” 보쑰적인 방어책에 λΆˆκ³Όν•˜λ‹€λŠ” 것을 κΌ­ κΈ°μ–΅ν•˜μž. λ³΄μ•ˆ 곡격은 μ‚¬μš©μžκ°€ μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό λΉ„ν™œμ„±ν™”ν•˜κ±°λ‚˜ ν΄λΌμ΄μ–ΈνŠΈ 검증을 μš°νšŒν•˜λŠ” λ°©λ²•μœΌλ‘œ μ‹œλ„λ  수 있기 λ•Œλ¬Έμ—, λͺ¨λ“  λ³΄μ•ˆ 검증은 μ„œλ²„ μΈ‘μ—μ„œλ„ λ°˜λ“œμ‹œ 이루어져야 ν•œλ‹€.