Web 감사
문제
독일어 원문
Nennen Sie zwei Änderungen an login.php, die zur Sicherheit beitragen, ohne die gewünschte Funktionalität zu beeinflussen.
한국어 해석
기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?
실제 시험에 제시된 Login 코드·사용자 표
index.html
1 <form action="http://api.example.com/login.php" method="GET">
2 Username: <input type="text" id="user" name="user">
3 Password: <input type="password" id="pw" name="pw">
4 <input type="submit" value="Login">
5 </form>
users
| login | password | role | |
|---|---|---|---|
| admin | king2026 | administrator | bob.king@example.com |
| alice | wonderland2002 | user | alice303@gmail.com |
| bob | king2026 | user | bob.king@gmail.com |
| charlie | 123456 | guest | ch.ar.lie.xxx@gmail.com |
| eve | 34@s5wa-rPg5.5 | readonly | eve.online.1997@gmail.com |
login.php
2 $user = $_GET['user'];
3 $pass = $_GET['pw'];
4 $sql = "SELECT * FROM users WHERE login = '$user' AND password = '$pass'";
5 $result = $conn->query($sql);
6 if ($result->num_rows > 0) {
7 echo "<div>Erfolgreich angemeldet!</div>";
8 } else {
9 echo "<div>Fehlgeschlagener Login für Nutzer: " . $user . "</div>";
10 }
출처: 실제 시험지 p13–14. 각 소문제에서 같은 code/data flow를 다시 추적합니다.
실제 시험 코드 취약 줄 하이라이터
실제 WiSe 25/26 시험 코드에서 취약한 줄을 선택하고 영향과 수정법을 말해 보세요.
단계별 힌트
막혔을 때만 한 단계씩 여세요. 정답을 바로 읽는 것보다 기억을 꺼내는 시간이 중요합니다.
- 첫 힌트: 이 문제는 서로 다른 두 해석기를 막는 문제다. DB에는 SQL 구조와 데이터를 분리하고, browser에는 HTML 문법 문자로 해석되지 않게 출력 encoding한다.
- username-only prepared statement와 `password_verify`를 쓴다.
- context-aware output encoding을 쓴다.
- 각 수정이 SQLi와 XSS 중 무엇을 막는지 연결한다.
- 함정: 'sanitize input' 한 문장으로 두 취약점을 퉁치지 않는다.
- 함정: client-side validation만 제시하지 않는다.
- 후속 점검: SQL context와 HTML context가 서로 다른 이유는?
채점 기준으로 내 답안 점검하기
- username-only prepared statement와 `password_verify`를 쓴다.
- context-aware output encoding을 쓴다.
- 각 수정이 SQLi와 XSS 중 무엇을 막는지 연결한다.
답안 슬롯 자가 점검 — 실제로 말하거나 쓴 항목만 체크하세요.
0/3 slots
정답과 핵심 해설 확인하기
첫째, username만 prepared statement로 조회한 뒤 저장된 verifier를 PHP `password_verify($pass, $storedHash)`로 검사한다. 둘째, 9행의 `$user`를 HTML context에 맞게 encode하거나 generic error를 사용한다.
- username-only prepared statement와 `password_verify`를 쓴다.
- context-aware output encoding을 쓴다.
- 각 수정이 SQLi와 XSS 중 무엇을 막는지 연결한다.
개념부터 다시 보는 상세 풀이
BEGINNER LESSON
웹 보안: 이 문제를 처음부터 이해하기
ZERO-BASE START
정말 아무것도 모른다고 가정하고 시작합니다
전문 용어를 알고 있다고 가정하지 않습니다. 먼저 일상적인 장면을 보고, 그 장면의 사람과 행동에 실제 보안 용어를 하나씩 붙인 뒤, 시스템에서 일어나는 순서를 따라갑니다.
기초 개념 01
SQL injection과 prepared statement
1타 강사식 시작: 이름은 잠시 가리고 장면부터 봅시다
주문서의 이름 칸에 ‘주문 취소하고 금고 열기’라고 썼을 때 직원이 그것을 이름이 아니라 새 지시로 실행하는 문제다. Prepared statement는 이름 칸을 끝까지 데이터 칸으로 고정한다.
지금은 이 비유를 완벽히 외울 필요가 없습니다. 누가 무엇을 가지고 있고, 무엇을 하려 하며, 어느 지점에서 문제가 생기는지만 찾으면 됩니다.
이제 실제 용어를 하나씩 붙여 봅시다
SQL은 database에 질문하는 언어다. 프로그램이 SQL 문자열과 사용자 입력을 단순히 이어 붙이면 입력의 따옴표나 연산자가 데이터가 아니라 SQL 문법으로 해석될 수 있다. 이것이 SQL injection이다. Prepared statement는 SQL 구조를 먼저 고정하고 사용자 값은 별도 parameter로 전달해 값이 명령 문법이 되지 못하게 한다.
TERMS FROM ZERO
전문 용어를 한 단어씩 풀기
아래 단어는 이미 안다고 가정하지 않습니다. 먼저 쉬운 뜻을 읽고, 본문에서 같은 단어가 나오면 이 정의로 다시 바꾸어 읽으세요.
SQL query
Database에 조회·삽입·변경 등을 요청하는 SQL 문장입니다.
SQL injection
공격자 입력이 SQL data가 아니라 query 구조와 명령으로 해석되는 취약점입니다.
Prepared statement
SQL 구조를 먼저 고정하고 사용자 값을 별도 parameter로 전달하는 방식입니다.
Parameter binding
입력값을 SQL syntax와 분리된 data slot에 연결하는 과정입니다.
프로그램이나 프로토콜 안에서는 다음 순서로 움직입니다.
- $_GET, $_POST 같은 입력 source를 찾는다.
- SQL 문자열 연결 또는 interpolation 지점을 찾는다.
- 입력이 query 구조를 바꿀 수 있는지 확인한다.
- Prepared statement와 bound parameter로 구조와 값을 분리한다.
- Database account 권한도 최소화한다.
왜 여기서 많이 틀릴까요?
따옴표를 몇 개 치환하는 blacklist나 client-side validation만으로 해결하려 하지 않는다.
조건을 생략하거나 서로 다른 기능을 같은 것으로 취급했는지 확인하세요. 정답 문장을 외우는 것보다 틀린 이유를 말할 수 있어야 변형 문제를 풀 수 있습니다.
기초 개념 02
XSS와 output encoding을 처음부터 이해하기
1타 강사식 시작: 이름은 잠시 가리고 장면부터 봅시다
설문 답변 칸에 쓴 문장을 사회자가 그대로 읽어야 하는데, 답변이 무대 지시문으로 해석되어 조명과 문을 조작하는 상황과 같다.
지금은 이 비유를 완벽히 외울 필요가 없습니다. 누가 무엇을 가지고 있고, 무엇을 하려 하며, 어느 지점에서 문제가 생기는지만 찾으면 됩니다.
이제 실제 용어를 하나씩 붙여 봅시다
Cross-Site Scripting(XSS)은 공격자 입력이 피해자 browser에서 신뢰된 사이트의 HTML 또는 JavaScript로 해석되어 실행되는 취약점이다. Reflected XSS는 request의 입력이 곧바로 response에 반사되는 형태다. 방어의 핵심은 출력 위치에 맞는 output encoding으로 특별한 문자를 데이터로만 해석하게 만드는 것이다.
TERMS FROM ZERO
전문 용어를 한 단어씩 풀기
아래 단어는 이미 안다고 가정하지 않습니다. 먼저 쉬운 뜻을 읽고, 본문에서 같은 단어가 나오면 이 정의로 다시 바꾸어 읽으세요.
XSS
공격자 입력이 victim browser에서 data가 아니라 HTML 또는 JavaScript code로 실행되는 취약점입니다.
Source
공격자 입력이 들어오는 URL, form, database record 같은 시작점입니다.
Sink
입력이 HTML이나 script로 해석될 수 있는 위험한 사용 지점입니다.
Output encoding
출력 context에서 특수문자가 code 문법이 아니라 data로 표현되도록 변환하는 방어입니다.
프로그램이나 프로토콜 안에서는 다음 순서로 움직입니다.
- $_GET 같은 사용자 입력 source를 찾는다.
- echo처럼 HTML response에 쓰는 sink를 찾는다.
- HTML body, attribute, URL, JavaScript 중 context를 판별한다.
- 해당 context용 encoding과 안전한 template API를 적용한다.
왜 여기서 많이 틀릴까요?
SQL injection 방어인 prepared statement를 XSS의 직접 해결책으로 쓰거나 client-side filter만 믿으면 안 된다.
조건을 생략하거나 서로 다른 기능을 같은 것으로 취급했는지 확인하세요. 정답 문장을 외우는 것보다 틀린 이유를 말할 수 있어야 변형 문제를 풀 수 있습니다.
핵심부터 말하면 이 문제는 서로 다른 두 해석기를 막는 문제다. DB에는 SQL 구조와 데이터를 분리하고, browser에는 HTML 문법 문자로 해석되지 않게 출력 encoding한다.
이 글에서 익힐 것
기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?
이 문항에 연결된 2개 기초 개념과 8개 전문 용어를 자신의 말로 설명한다.
정의만 외우지 않고 구체적인 입력·message·code 흐름을 단계별로 재현한다.
시험 답안에서 결론과 근거, 조건 또는 한계를 함께 쓴다.
이 문제가 어려운 이유
문제 문장은 짧지만 초보자가 이미 안다고 가정하는 용어와 중간 단계가 숨어 있습니다. 이 페이지에서는 ‘기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?’를 바로 외우지 않고, 아래 연결 개념을 일상 장면에서 시작해 실제 시스템 순서로 바꿉니다.
문제가 묻는 것
기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?
문제가 요구하는 동사와 답의 개수를 먼저 표시하고, 등장 주체·입력·처리 순서·보안 효과·남는 한계를 차례로 적습니다.
먼저 알아야 할 개념
-
SQL injection과 prepared statement
SQL은 database에 질문하는 언어다. 프로그램이 SQL 문자열과 사용자 입력을 단순히 이어 붙이면 입력의 따옴표나 연산자가 데이터가 아니라 SQL 문법으로 해석될 수 있다. 이것이 SQL injection이다. Prepared statement는 SQL 구조를 먼저 고정하고 사용자 값은 별도 parameter로 전달해 값이 명령 문법이 되지 못하게 한다.
주문서의 이름 칸에 ‘주문 취소하고 금고 열기’라고 썼을 때 직원이 그것을 이름이 아니라 새 지시로 실행하는 문제다. Prepared statement는 이름 칸을 끝까지 데이터 칸으로 고정한다.
-
XSS와 output encoding을 처음부터 이해하기
Cross-Site Scripting(XSS)은 공격자 입력이 피해자 browser에서 신뢰된 사이트의 HTML 또는 JavaScript로 해석되어 실행되는 취약점이다. Reflected XSS는 request의 입력이 곧바로 response에 반사되는 형태다. 방어의 핵심은 출력 위치에 맞는 output encoding으로 특별한 문자를 데이터로만 해석하게 만드는 것이다.
설문 답변 칸에 쓴 문장을 사회자가 그대로 읽어야 하는데, 답변이 무대 지시문으로 해석되어 조명과 문을 조작하는 상황과 같다.
예제로 확인하기
-
SQL injection과 prepared statement을 이 문제에 대입하기
주문서의 이름 칸에 ‘주문 취소하고 금고 열기’라고 썼을 때 직원이 그것을 이름이 아니라 새 지시로 실행하는 문제다. Prepared statement는 이름 칸을 끝까지 데이터 칸으로 고정한다.
$_GET, $_POST 같은 입력 source를 찾는다.
SQL 문자열 연결 또는 interpolation 지점을 찾는다.
입력이 query 구조를 바꿀 수 있는지 확인한다.
Prepared statement와 bound parameter로 구조와 값을 분리한다.
Database account 권한도 최소화한다.
위 순서를 문제 문장 ‘기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?’에 적용하면, 이 문항의 핵심 결론은 첫째, username만 prepared statement로 조회한 뒤 저장된 verifier를 PHP `password_verify($pass, $storedHash)`로 검사한다. 둘째, 9행의 `$user`를 HTML context에 맞게 encode하거나 generic error를 사용한다.입니다.
-
XSS와 output encoding을 처음부터 이해하기을 이 문제에 대입하기
설문 답변 칸에 쓴 문장을 사회자가 그대로 읽어야 하는데, 답변이 무대 지시문으로 해석되어 조명과 문을 조작하는 상황과 같다.
$_GET 같은 사용자 입력 source를 찾는다.
echo처럼 HTML response에 쓰는 sink를 찾는다.
HTML body, attribute, URL, JavaScript 중 context를 판별한다.
해당 context용 encoding과 안전한 template API를 적용한다.
위 순서를 문제 문장 ‘기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?’에 적용하면, 이 문항의 핵심 결론은 첫째, username만 prepared statement로 조회한 뒤 저장된 verifier를 PHP `password_verify($pass, $storedHash)`로 검사한다. 둘째, 9행의 `$user`를 HTML context에 맞게 encode하거나 generic error를 사용한다.입니다.
정답까지 사고 과정
username-only prepared statement와 `password_verify`를 쓴다.
context-aware output encoding을 쓴다.
각 수정이 SQLi와 XSS 중 무엇을 막는지 연결한다.
시험장에서는 이렇게 쓰기
핵심 해설
첫째, username만 prepared statement로 조회한 뒤 저장된 verifier를 PHP `password_verify($pass, $storedHash)`로 검사한다. 둘째, 9행의 `$user`를 HTML context에 맞게 encode하거나 generic error를 사용한다.
시험 답안으로 정리하기
username-only prepared statement와 `password_verify`를 쓴다.
context-aware output encoding을 쓴다.
각 수정이 SQLi와 XSS 중 무엇을 막는지 연결한다.
자주 틀리는 지점
'sanitize input' 한 문장으로 두 취약점을 퉁치지 않는다.
client-side validation만 제시하지 않는다.
채점 포인트
username-only prepared statement와 `password_verify`를 쓴다.
context-aware output encoding을 쓴다.
각 수정이 SQLi와 XSS 중 무엇을 막는지 연결한다.
한 줄로 기억하기
이 문제는 서로 다른 두 해석기를 막는 문제다. DB에는 SQL 구조와 데이터를 분리하고, browser에는 HTML 문법 문자로 해석되지 않게 출력 encoding한다.
스스로 확인하기
SQL context와 HTML context가 서로 다른 이유는?
AI 구두시험용 프롬프트
한 문항만 풀어라. 먼저 정답을 열지 말고 90초 안에 답안을 말한 뒤, css-ws2025-26-web-php-006의 채점 프레임으로 스스로 채점하라. 문제: 기능을 유지하면서 login.php를 안전하게 하는 변경 두 가지는?
학습 기록