새 출제 기준 첫 회차. Python 3문항, 함수 포인터 %x, FOREIGN KEY 빈칸 5개, 비기능 요구사항. 프로그래밍이 7문항으로 줄었다
왜 이걸 하나 — 세트는 시험장과 같은 조건에서만 숫자가 된다. 조건은 E01 과 같다.
규칙은 E01 진단의 01절 그대로다. 시작을 누르면 150분이 돌고, 1회독 100분 · 2회독 40분 · 검토 10분으로 나눈다. 한 문항에 5분이 넘으면 답 칸을 비우고 넘어가며, 정답은 20문항을 다 적은 뒤에 연다.
이 회차의 배점은 프로그래밍 7문항(35점) · SQL·DB 4문항(20점) · SW공학 4문항(20점) · 보안 3문항(15점) · 네트워크 2문항(10점)이다. 코드 문항 수만큼 5분씩을 1회독에서 먼저 떼어 두고, 남는 시간을 용어에 쓴다. 용어는 아는 것을 바로 적고 모르는 것은 비운다 — 용어에서 고민하는 시간이 코드 한 문항의 값이다.
왜 이걸 하나 — 20문항을 한 번에 150분 안에 푸는 것 자체가 연습이다. 분야 장의 문제와 같은 문항이어도 조건이 다르다.
시작을 누르면 시계가 돌고 화면을 닫아도 이어진다. 다 적은 뒤 문항마다 정답 보기 → 맞았다 · 틀렸다를 누르면 위 막대에 점수와 분야별 결과가 모인다. 이 세트에서 채점한 기록은 분야 장의 같은 문항에도 그대로 보인다.
다음 Java 프로그램을 실행했을 때 출력되는 값을 쓰시오.
답 — 2. a.g() 는 A 에 적힌 g() 를 돌리고, 그 안의 f("a") 는 컴파일 때 f(Object) 로 정해진 뒤 실행 때 B 가 덮어쓴 f(Object) 로 간다.
원리 — 자바는 메서드를 두 번 고른다. 첫째, 컴파일 때 "어느 이름 · 어느 매개변수 꼴인가"를 고른다(오버로딩 선택). 둘째, 실행 때 "그 꼴을 가진 메서드 중 실제 객체의 것"을 고른다(오버라이딩). 편지에 비유하면 봉투의 주소(시그니처)는 부칠 때 정해지고, 그 집에 누가 사는지(실제 객체)는 배달할 때 본다. 봉투를 쓰는 곳은 A 안이라 A 가 아는 f(Object) 라고만 적힌다. B 의 f(String) 은 이름만 같을 뿐 다른 봉투라 후보에도 못 든다.
따라가기
A a = new B(); — 겉은 A, 속은 Ba.g() — g 는 A 에만 있으니 A.g 가 돈다f("a") — A 클래스 안에서 컴파일됐고 A 가 아는 f 는 f(Object) 하나. 봉투 = f(Object)헷갈리는 자리 — "a" 는 String 이니 B.f(String) 이 더 잘 맞지 않나? 아니다. 오버로딩 선택은 A 안에서 끝났고 그때 f(String) 은 없었다. 답을 3 으로 적는 것이 이 문제의 함정이다. 2024년 3회 18번(제네릭 T 가 Object 로 지워져 print(Object) 가 골라짐)과 같은 규칙이다.
복원 코드를 JDK 17 로 컴파일 · 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 C 프로그램의 실행 결과를 쓰시오.
답 — 106.00. 두 함수는 같은 배열의 평균 53.0 을 각각 돌려주고, %.2f 가 소수 둘째 자리까지 찍는다.
원리 — 함수 매개변수의 int p[] 와 int *p 는 완전히 같은 것이다. 배열을 넘기면 복사되지 않고 첫 칸 주소만 넘어가므로, 어느 쪽으로 적어도 함수 안의 p 는 포인터다. 따라서 p[i] 와 *(p + i) 도 같은 칸을 읽는다 — 대괄호는 "주소에 i 를 더해 연다"의 다른 표기일 뿐이다. 두 함수는 이름과 표기만 다르고 하는 일이 같아 결과가 같다. (double) 은 정수를 실수로 바꿔 나눗셈에서 소수점이 잘리지 않게 한다.
따라가기
%.2f → 106.00헷갈리는 자리 — 106 이나 106.0 으로 적는 것. 서식 문자열이 답의 일부라 소수점 아래 두 자리까지 적어야 한다. 또 "arr2 가 포인터라 다른 값이 나온다"고 넘겨짚는 것 — 표기가 다를 뿐 같은 칸이다. (double) 을 빼면 av 가 double 이라 어차피 실수 나눗셈이지만, av 까지 int 였다면 53 이 아니라 소수점이 잘린 값이 나온다 — 나눗셈은 두 쪽 중 하나만 실수여도 실수로 계산된다.
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
① 추상부와 구현부를 분리해 독립적으로 확장할 수 있게 하는 구조 패턴 ② 객체 상태 변화 시 등록된 객체들에게 자동으로 통지하는 행위 패턴
답 — ① Bridge(브리지) ② Observer(옵저버). "추상부와 구현부 분리"와 "상태 변화 자동 통지"가 각각의 표지다.
원리 — 브리지는 구조 패턴이다. "도형(원 · 사각형)"과 "그리는 방식(벡터 · 래스터)"처럼 두 축이 있을 때 상속으로 조합하면 클래스가 곱셈으로 늘어난다(원벡터 · 원래스터 · 사각벡터…). 브리지는 추상부(도형)가 구현부(그리기)를 필드로 가리키게 해서 두 축을 따로 확장한다 — 다리로 잇는다. 옵저버는 행위 패턴이다. 주제(Subject)가 관찰자(Observer) 목록을 갖고, 상태가 바뀌면 notify() 로 등록된 모두에게 알린다 — 주제는 관찰자가 누구인지 몰라도 된다. 이벤트 리스너 · 발행/구독이 이것이다.
따라가기
헷갈리는 자리 — 브리지를 어댑터로 적는 것. 어댑터는 "안 맞는 것을 나중에 맞춤", 브리지는 "처음부터 두 축을 갈라 설계"다. 옵저버를 미디에이터로 적는 것 — 미디에이터는 여러 객체의 대화를 중재자 하나에 모으고, 옵저버는 한 주제의 변화를 여럿에게 뿌린다.
GoF 책 Design Patterns 의 패턴 정의(생성 5 · 구조 7 · 행위 11)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
데이터베이스 설계 순서를 나열하시오 (요구사항 분석 / 구현 / 논리적 설계 / 개념적 설계 / 물리적 설계)
답 — 요구사항 분석 → 개념적 설계 → 논리적 설계 → 물리적 설계 → 구현. 2023년 2회 3번에 구현이 더해진 다섯 단계다.
원리 — 무엇을 담을지 듣고(요구사항), 개체 · 관계 그림을 그리고(개념 — E-R), DBMS 에 맞는 표로 옮기고(논리 — 정규화), 저장 구조를 정하고(물리 — 인덱스 · 파일), 마지막에 실제 DDL 로 만든다(구현). 뒤로 갈수록 특정 DBMS · 하드웨어에 매인다. 앞 단계의 결과물이 뒤 단계의 입력이라 순서를 바꿀 수 없다.
따라가기
헷갈리는 자리 — 논리와 물리를 바꾸는 것. "정규화"는 논리, "인덱스 · 접근 경로"는 물리다. 보기의 낱말을 그대로 순서만 바꿔 적는다.
교재 정의(관계형 모델 · 정규화 · 트랜잭션 표준 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
비기능 요구사항 분류: ① 여러 OS·다양한 포맷 지원 ② 적은 메모리 사용, 터치스크린 등 자원 관련 ③ 1초 이내 응답 등 속도 관련
답 — ① 운영 요구사항 ② 자원 요구사항 ③ 성능 요구사항. "어떤 환경에서 도나 · 무엇을 얼마나 쓰나 · 얼마나 빠르나"로 갈린다.
원리 — 요구사항은 "무엇을 하는가"(기능 요구사항)와 "어떤 조건에서 어떻게"(비기능 요구사항)로 나뉜다. 비기능 요구사항은 다시 여러 갈래다. 성능 요구사항은 응답 시간 · 처리량 · 동시 사용자 같은 속도와 양이다 — "1초 이내 응답". 자원 요구사항은 메모리 · 저장 공간 · CPU · 입력 장치처럼 시스템이 쓰는 자원에 대한 제약이다 — "메모리 적게, 터치스크린 지원". 운영 요구사항은 시스템이 놓일 운영 환경에 대한 것이다 — "여러 OS 에서 돌고 다양한 파일 포맷을 지원". 이 밖에 보안 · 신뢰성 · 사용성 · 이식성 · 유지보수성 요구사항이 같은 묶음에 든다.
따라가기
헷갈리는 자리 — ①을 이식성(portability) 요구사항으로 적는 것. 여러 OS 지원은 이식성으로도 읽히지만, 이 문제의 보기 구성(운영 · 자원 · 성능)에서는 운영 요구사항이 정답으로 복원돼 있다. 복원 문제라 실제 보기 문구가 달랐을 수 있으니 "OS · 포맷 = 운영 환경" 으로 묶어 기억한다.
표준 · 교재 정의(운영체제 · 리눅스 명령 · 웹 · 클라우드 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
HDLC의 프레임 종류 3가지(①②③)와 동작 모드 2가지(④⑤: 균형 모드 / 종국이 허가 없이 응답 가능한 모드)를 쓰시오.
답 — ① 정보 ② 감독 ③ 비번호 ④ 비동기 균형 모드(ABM) ⑤ 비동기 응답 모드(ARM). 2023년 2회 19번이 그대로 다시 나왔다.
원리 — HDLC 프레임은 데이터를 나르는 정보(I), 제어만 하는 감독(S), 연결 관리용 비번호(U) 셋이다. 모드는 명령권으로 나뉜다 — NRM 은 주국만, ARM 은 종국도 허가 없이 응답, ABM 은 양쪽 대등. 문제가 "균형 모드"라고 하면 ABM, "종국이 허가 없이 응답"이라 하면 ARM 이다.
따라가기
헷갈리는 자리 — NRM 을 ⑤ 에 적는 것. NRM 은 허가를 받아야 응답한다. 같은 문제가 3년 만에 그대로 나온 만큼 프레임 3 · 모드 3 여섯 낱말을 한 줄로 외운다.
표준 · 교재 정의(OSI · TCP/IP · IEEE · RFC 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
기업·기관의 정보보호 관리체계가 기준에 적합한지 정부 지정 인증기관이 심사하여 인증하는 제도는? (영문 약자)
답 — ISMS. 정보보호 관리체계가 기준에 맞는지 정부 지정 기관이 심사해 인증하는 제도다.
원리 — 기업이 정보를 지키는 "체계"(정책 · 조직 · 절차 · 통제)를 갖췄는지 한국인터넷진흥원 등 지정 기관이 심사해 인증서를 주는 것이 ISMS(Information Security Management System) 인증이다. 개인정보 보호까지 함께 보면 ISMS-P 다. 일정 규모 이상의 사업자는 의무이고 유효 기간은 3년, 매년 사후 심사를 받는다. 국제 표준은 ISO 27001 이다. "관리체계 · 인증 · 정부 지정 기관"이 표지다.
따라가기
헷갈리는 자리 — ISO 27001(국제 표준)이나 PIMS(옛 개인정보 인증, 지금은 ISMS-P 로 통합)를 적는 것. 국내 제도의 영문 약자는 ISMS 다.
표준 · 교재 정의(암호 · 인증 · 접근 통제 용어)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
다음 C 프로그램을 실행했을 때 출력되는 값을 쓰시오.
답 — 20. 함수 포인터로 dummy 를 불러 배열의 둘째 칸 주소를 받고, 그 값 32 를 16진수로 찍는다.
원리 — int *(*fn)(int *) 는 "int 포인터를 받아 int 포인터를 돌려주는 함수"를 가리키는 포인터다. 구조체 멤버 fn 에 dummy 를 넣으면 mine.fn(n) 은 dummy(n) 과 같다. dummy 는 받은 주소에 1 을 더해 돌려주므로 배열의 다음 칸(&n[1]) 주소다. 앞의 별표가 그 칸을 열어 32 가 나온다. %x 는 값을 16진수로 찍는 서식이라 32 는 0x20, 화면에는 20 이다.
따라가기
* → 32%x → 32 = 2 × 16 + 0 → 20헷갈리는 자리 — 32 를 그대로 적는 것. 서식이 %d 가 아니라 %x 다. 함수 포인터 선언이 낯설어 d + 1 을 값 17 로 읽는 것 — d 는 주소라 +1 은 한 칸 옆이다. 첫 칸 16 을 16진수로 바꾼 10 도 오답이다(dummy 가 한 칸 옮겼다).
복원 코드를 gcc(도커 alpine)로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
STUDENT 테이블(총 200명, 학과 3개)에서: ① SELECT COUNT(*) FROM STUDENT; ② SELECT COUNT(DISTINCT 학과) FROM STUDENT; ③ SELECT COUNT(DISTINCT 학과) FROM STUDENT WHERE 학과='전산과'; 각각의 결과는?
답 — ① 200 ② 3 ③ 1. COUNT(*) 는 전체 행, COUNT(DISTINCT 학과) 는 서로 다른 학과 수, WHERE 로 한 학과만 남기면 그 수는 1 이다.
원리 — COUNT(*) 는 조건을 통과한 행의 수다(200 명 → 200). DISTINCT 는 중복을 지운다 — 200 행의 학과 값 중 서로 다른 것만 세면 학과 수 3 이다. ③ 은 WHERE 로 전산과 행만 남긴 뒤 그 안의 서로 다른 학과 값을 세니, 전산과 하나뿐이라 1 이다. 행 수(몇 명)와 종류 수(몇 학과)를 나누는 것이 전부다.
따라가기
헷갈리는 자리 — ③ 을 "전산과 학생 수"로 읽고 인원을 적는 것. DISTINCT 학과이므로 종류 수 1 이다. ② 를 200 으로 적는 것 — DISTINCT 가 있다. 세 문항이 COUNT 의 세 가지 쓰임을 정확히 나눠 묻는다. 학과 값에 NULL 인 학생이 있었다면 COUNT(DISTINCT 학과)는 NULL 을 안 세므로 ② 가 달라질 수 있다 — 문제는 그런 행이 없다고 본다.
표를 sqlite 3.49 에 넣고 같은 SQL 을 실행해 결과를 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.
다음 Python 프로그램을 실행했을 때 출력되는 값을 쓰시오.
답 — 9A7A5A3A1A. 0~9 리스트를 뒤에서부터 두 칸씩 건너뛰며 꺼내고, 각 값 뒤에 A 를 붙여 한 줄로 찍는다.
원리 — list(range(10)) 은 [0, 1, …, 9] 다. 슬라이스 [::-2] 는 시작 · 끝을 비우고 스텝을 −2 로 준 것이라 "끝에서 시작해 두 칸씩 거꾸로"다 — 9, 7, 5, 3, 1. print(c, end='A') 는 줄바꿈 대신 A 를 붙이라는 뜻이라 값들이 한 줄에 A 로 이어진다. 마지막 print() 는 빈 줄바꿈 하나를 찍어 줄을 끝낸다.
따라가기
헷갈리는 자리 — 스텝이 음수인데 앞에서부터 0, 2, 4, … 로 적는 것. 음수 스텝은 시작이 끝이다. 마지막 1 뒤의 A 를 빼먹는 것 — end='A' 는 매 print 마다 붙는다. 마지막 print() 는 글자를 안 찍으므로 답에 들어가지 않는다.
복원 코드를 Python 3.12 로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
두 호스트의 IP 주소와 서브넷 마스크를 보고 각 호스트가 속한 네트워크 주소를 CIDR 표기법으로 쓰시오.
| 호스트 | IP 주소 | 서브넷 마스크 |
|---|---|---|
| a | 192.168.11.20 | 255.255.254.0 |
| b | 192.168.12.200 | 255.255.254.0 |
답 — a. 192.168.10.0/23 b. 192.168.12.0/23. 마스크 254 는 셋째 옥텟을 2 씩 묶으므로 11 은 10~11, 12 는 12~13 묶음이다.
원리 — 255.255.254.0 은 앞 23비트가 네트워크 부분(/23)이다. 셋째 옥텟 254 = 1111 1110 이라 묶음 크기가 256 − 254 = 2 — 0~1, 2~3, …, 10~11, 12~13. 네트워크 주소는 묶음의 첫 값에 마지막 옥텟 0 을 붙인 것이고, CIDR 표기는 그 뒤에 /23 을 붙인다. 두 호스트는 이웃한 묶음이라 서로 다른 네트워크다.
따라가기
헷갈리는 자리 — a 를 192.168.11.0/23 으로 적는 것. 11 은 묶음의 시작이 아니라 끝이다 — 짝수에서 시작하는 2 묶음이라는 것을 표로 확인한다. /23 을 빼먹으면 "CIDR 표기"라는 요구를 못 채운다.
파이썬 ipaddress 로 네트워크 · 범위를 계산해 같은 값을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.
다음 Python 프로그램을 실행했을 때 출력되는 값을 쓰시오.
답 — 10. b = m[:] 는 겉 리스트만 새로 만들고 안쪽 리스트는 공유하므로, b 를 통해 늘린 안쪽 리스트가 m 에서도 보여 길이 합이 1 + 2 + 3 + 4 다.
원리 — m = [[x] for x in a] 는 [[1], [2], [3], [4]] 다. m[:] 는 얕은 복사 — 바깥 상자는 새로 만들지만 그 안의 네 리스트는 원래 것을 그대로 가리킨다. 그래서 b[i + 1] += b[i] 는 안쪽 리스트를 제자리에서 늘리는 것이고(리스트의 += 는 새 리스트를 만들지 않고 이어 붙인다), 그 안쪽 리스트는 m 도 같이 들고 있다. 결국 m 의 안쪽 리스트들이 [1], [2, 1], [3, 2, 1], [4, 3, 2, 1] 로 커진다. 완전히 떼어 놓으려면 copy.deepcopy 가 필요하다.
따라가기
헷갈리는 자리 — [:] 를 완전 복사로 보고 m 이 안 바뀌었다며 4 를 적는 것. 얕은 복사는 안쪽을 공유한다. 반대로 b[i + 1] = b[i + 1] + b[i] 였다면 새 리스트가 만들어져 b 만 바뀌고 답은 4 였다 — += 와 = 의 차이까지가 이 문제다.
복원 코드를 Python 3.12 로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 두 테이블과 SQL문을 보고 반환되는 값을 쓰시오.
employee 테이블
| dep_id |
|---|
| 10 |
| 20 |
| 20 |
dept 테이블
| dept_id | budget |
|---|---|
| 10 | 100 |
| 20 | 300 |
| 30 | 200 |
답 — 2. 예산 평균 200 보다 큰 부서는 20(300)뿐이고, 그 부서 직원이 두 명이다.
원리 — 서브쿼리 SELECT AVG(budget) FROM dept 는 하나의 값(200)을 돌려주고, 바깥 조건은 d.budget > 200 이 된다. JOIN … ON e.dep_id = d.dept_id 는 직원 행마다 부서 정보를 붙인다 — 직원이 세 행이니 조인 결과도 세 행이고, 그중 부서 예산이 200 을 넘는 행만 센다. 부서 30 은 직원이 없어 조인에 아예 안 나온다.
따라가기
헷갈리는 자리 — 부서 수로 세어 1(부서 20 하나)을 적는 것. COUNT(*) 는 조인된 직원 행을 센다. 200 을 "이상"으로 보고 부서 30 까지 넣는 것 — > 는 초과이고, 30 은 직원이 없어 어차피 0 행이다.
표를 sqlite 3.49 에 넣고 같은 SQL 을 실행해 결과를 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 표 · 값이 실제와 다를 수 있다.
다음 Python 프로그램에 HumanDev를 입력했을 때 출력되는 값을 쓰시오.
답 — veDamuH. 입력 HumanDev 를 뒤집어 veDnamuH 로 만든 뒤 o · n · g 를 빼면 n 하나가 빠진다.
원리 — i.split() 은 공백으로 나누는데 "HumanDev" 엔 공백이 없어 조각이 하나뿐이고, ''.join(x) 로 다시 붙여도 그대로다. y[::-1] 은 문자열 뒤집기. ''.join(c for c in … if c not in 'ong') 은 글자를 하나씩 보며 o · n · g 중 하나가 아닌 것만 모아 붙인다. 대소문자를 구분하므로 대문자 D · H 는 그대로 남는다.
따라가기
헷갈리는 자리 — 뒤집기 전에 글자를 빼거나, 'ong' 을 한 덩어리 문자열로 보고 "ong" 이 없으니 아무것도 안 뺀다고 보는 것 — c not in 'ong' 은 글자 하나가 그 세 글자 중 하나인지다. 대문자 H 는 안 빠진다는 것도 확인한다.
복원 코드를 Python 3.12 로 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
통합 테스트: ① 하향식에서 미완성 하위 모듈을 대신하는 것 ② 상향식에서 상위 모듈을 대신해 호출하는 것
답 — ① 스텁(Stub) ② 드라이버(Driver). 2023-2-07 과 같은 문제다.
원리 — 통합 테스트에서 아직 없는 모듈의 자리를 채우는 가짜를 테스트 하네스라 한다. 하향식은 위에서 아래로 내려가니 "아직 안 만든 아래"가 비어 있다 — 위 모듈이 호출하면 미리 정한 값을 돌려주는 가짜 하위가 스텁이다. 상향식은 아래에서 위로 올라가니 "아직 안 만든 위"가 비어 있다 — 아래 모듈을 호출해 검사를 시작해 주는 가짜 상위가 드라이버다. 스텁은 "불려서 답하는 것", 드라이버는 "부르는 것"이다. 실무의 목(mock) 객체가 스텁의 확장이고, JUnit 테스트 메서드가 드라이버 역할이다.
따라가기
헷갈리는 자리 — 방향과 짝을 바꾸는 것. "하향식 → 하위가 없다 → 스텁", "상향식 → 상위가 없다 → 드라이버". 하 · 하, 상 · 상으로 첫 글자가 맞아떨어진다.
표준 · 교재 정의(ISTQB 용어 · 커버리지 6단계 · 테스트 수준)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
표적이 자주 방문하는 웹사이트를 미리 감염시켜 놓고, 방문 시 악성코드에 감염시키는 공격 기법은? (사자가 물웅덩이에서 사냥감을 기다리는 것에서 유래)
답 — 워터링 홀(Watering Hole). 표적이 자주 가는 사이트를 미리 감염시켜 놓고 방문하기를 기다리는 공격이다.
원리 — 표적 조직에 직접 침입하기 어려우면 그 사람들이 늘 들르는 사이트(협회 · 커뮤니티)를 먼저 해킹해 악성코드를 심는다. 표적이 평소처럼 방문하는 순간 감염된다 — 사자가 물웅덩이 옆에 숨어 물 마시러 오는 사냥감을 기다리는 데서 이름이 왔다. 사용자가 이상한 링크를 누른 것도 아니라 눈치채기 어렵고, APT 의 초기 침투 수단으로 자주 쓰인다.
따라가기
헷갈리는 자리 — 피싱(가짜 사이트로 유인)이나 파밍(DNS 조작)과 섞는 것. 워터링 홀은 "진짜 사이트를 감염"시키고 유인 메일이 없다는 것이 다르다.
표준 · 교재 정의(공격 기법 · 보안 솔루션 · 시큐어 코딩 가이드)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
다음 Java 프로그램을 실행했을 때 출력되는 값을 쓰시오.
답 — 1123. 왼쪽부터 계산해 9 + 2 = 11 이 먼저 정수로 더해지고, 그다음부터는 문자열 붙이기라 "11" + "2" + "3" 이다.
원리 — + 는 두 쪽이 모두 숫자면 덧셈이고, 한쪽이라도 문자열이면 붙이기다. 그리고 왼쪽에서 오른쪽으로 하나씩 계산한다. x1 + x2 는 둘 다 int 라 11(덧셈), 그 결과 11 과 "2" 는 한쪽이 문자열이라 "112"(붙이기), 이어서 "112" + "3" → "1123". 문자열이 한 번 끼어든 뒤부터는 되돌아가지 않는다. 괄호가 없으니 순서를 바꿔 읽을 여지가 없다.
따라가기
헷갈리는 자리 — 전부 문자열로 보고 9223 을 적는 것(첫 덧셈은 정수). 전부 숫자로 보고 16 을 적는 것("2" 와 "3" 은 문자열). "2" + x1 + x2 였다면 "292" 가 되듯 순서가 답을 바꾼다. 괄호로 x1 + (x2 + "2") 라고 묶으면 안쪽이 먼저 붙기라 "9223" 이 된다 — 괄호 유무도 본다.
복원 코드를 JDK 17 로 컴파일 · 실행해 같은 출력을 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 변수명이 실제와 다를 수 있다.
다음 조건을 만족하도록 PLAYER 테이블의 외래키 제약 조건을 완성하시오.
외래키 제약 조건의 이름은 TEAM_TF이다.
PLAYER 테이블의 TEAM_ID가 외래키다.
TEAM 테이블의 TEAM_ID2를 참조한다.
답 — ① CONSTRAINT ② FOREIGN ③ TEAM_ID ④ REFERENCES ⑤ TEAM_ID2. 이름 붙은 외래키 제약을 적는 정해진 꼴이다.
원리 — 외래키는 "이 열의 값은 저 테이블의 저 열에 있는 값이어야 한다"는 약속이다. 테이블을 만들 때 적는 꼴은 CONSTRAINT 제약이름 FOREIGN KEY (내 열) REFERENCES 상대테이블(상대 열) 이다. CONSTRAINT 이름은 나중에 지울 때(ALTER TABLE … DROP CONSTRAINT 이름) 부르기 위해 붙인다. 문제가 준 조건 셋 — 이름 TEAM_TF, 내 열 TEAM_ID, 상대 TEAM 의 TEAM_ID2 — 을 그 자리에 넣으면 된다.
따라가기
헷갈리는 자리 — ⑤ 에 TEAM_ID 를 적는 것. 상대 테이블의 열 이름은 TEAM_ID2 라고 문제가 못 박았다. ④ 에 REFERENCE(단수)를 적는 것 — REFERENCES 다. PRIMARY KEY 처럼 FOREIGN KEY 도 두 낱말이라 ② 는 FOREIGN 하나다.
답의 SQL 을 sqlite 3.49 에서 실행해 확인했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장 · 열 이름이 실제와 다를 수 있다.
원본 파일을 가리키는 바로가기(링크) 파일을 악용하여, 링크를 조작해 공격자가 의도한 파일에 접근하게 만드는 공격은? (보기 선택형)
답 — 심볼릭 링크 공격(Symbolic Link Attack). 바로가기 파일이 가리키는 곳을 바꿔 프로그램이 엉뚱한 파일을 읽거나 쓰게 만드는 공격이다.
원리 — 심볼릭 링크는 다른 파일을 가리키는 바로가기다. 권한 높은 프로그램이 임시 파일 이름으로 무언가를 쓸 때, 공격자가 먼저 그 이름의 링크를 만들어 /etc/passwd 같은 중요 파일을 가리키게 해 두면 프로그램은 링크를 따라가 그 파일을 덮어쓴다. 검사 시점과 사용 시점 사이의 틈(경쟁 조건, TOCTOU)을 이용하는 것이다. 막으려면 임시 파일을 안전한 방식으로 만들고 링크를 따라가지 않게 한다.
따라가기
헷갈리는 자리 — 경로 조작(path traversal, ../ 로 상위 폴더 접근)과 섞는 것. 그것은 입력 문자열로 경로를 바꾸는 것이고, 심볼릭 링크 공격은 파일 시스템의 링크를 바꾼다. 보기 선택형이면 낱말 그대로 고른다.
표준 · 교재 정의(공격 기법 · 보안 솔루션 · 시큐어 코딩 가이드)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
응집도 3종: ① 다수의 관련 기능이 순서에 따라 차례대로 수행됨 ② 동일한 입출력 데이터를 사용하는 기능들이 모임 ③ 단일 기능만 수행
답 — ① 절차적 응집도 ② 교환(통신)적 응집도 ③ 기능적 응집도. "순서대로 · 같은 자료 · 단일 기능"이 열쇠말이다.
원리 — 응집도 7단계는 모듈 안의 것들이 "왜 같이 있는가"로 구분한다. 우연적(이유 없음) < 논리적(비슷해서, 플래그로 골라 씀) < 시간적(같은 시점) < 절차적(순서대로 실행) < 교환적(같은 입출력 자료) < 순차적(앞 출력 = 뒤 입력) < 기능적(한 가지 일). 절차적은 "A 다음 B 를 한다"는 순서만 있고 자료 연결은 없다. 교환적은 같은 자료를 여럿이 다룬다 — 예: 같은 고객 레코드로 이름도 찍고 주소도 찍는다. 기능적은 모듈 전체가 오직 한 가지 목적(제곱근 계산)만 한다 — 가장 좋다.
따라가기
헷갈리는 자리 — ①을 순차적으로 적는 것. 순차적은 "출력이 다음 입력"이라는 자료 연결이 있어야 한다. 순서만 있으면 절차적이다. 그리고 교환적은 "통신적(Communicational)"이라고도 부르니 둘 다 정답 처리된다. ②를 시간적으로 적는 실수도 있다 — 시간적은 "같은 때"이지 "같은 자료"가 아니다. 자료라는 말이 보이면 교환적 아니면 순차적 둘 중 하나다.
표준 · 교재 정의(결합도 6단계 · 응집도 7단계 · UML 2.x 다이어그램 분류)와 대조했다. 복원 출처 grandlife.co.kr(2026-09-14) — 공식 원문이 아니라 문장이 실제와 다를 수 있다.
왜 이걸 하나 — 점수보다 어느 장으로 돌아가느냐가 결과다. 문항마다 가는 장이 정해져 있다.
코드 7문항 중 C 2 · Java 2 · Python 3 이다. 1번은 B 의 f(Object) 가 오버라이딩이고 f(String) 은 오버로딩이라 g() 안의 f("a") 는 A 에서 컴파일된 f(Object) 로 묶여 2 다. 8번은 함수 포인터 멤버가 d + 1 을 돌려줘 32 를 %x 로 찍으면 20. 12번은 m[:] 가 겉만 복사라 안쪽 리스트가 함께 커져 10 이다.
SQL·DB 는 9번 COUNT(*) · COUNT(DISTINCT) 세 값, 13번 AVG 서브쿼리 조인 건수 2, 18번 CONSTRAINT · FOREIGN · TEAM_ID · REFERENCES · TEAM_ID2 다섯 칸, 4번 설계 5단계다. 18번은 칸마다 점수가 있어 구문 순서만 알면 채운다.
용어는 SW공학 4(Bridge/Observer · 비기능 요구사항 3칸 · 스텁/드라이버 · 응집도 3칸) · 보안 3(ISMS · 워터링 홀 · 심볼릭 링크) · 네트워크 2(HDLC 5칸 · /23 CIDR)다. 5번 비기능 요구사항의 운영 · 자원 · 성능은 이 회차에 처음 나온 낱말이라 E16 표에 넣어 두었다.
틀린 문항의 「가는 장」을 열면 그 문항이 04절에 그대로 있고, 앞뒤로 같은 꼴의 문항이 붙어 있다. 몰라서 틀렸으면 그 장 03절부터, 알았는데 틀렸으면 05절만 읽는다. 판정 기준은 E01 의 03절 표와 같다.
| 문항 | 분야 | 가는 장 | 무엇을 묻나 |
|---|---|---|---|
| 1 | Java | E05 | Object 매개변수 오버라이딩 vs String 오버로딩 |
| 2 | C | E02 | 배열 평균 두 번 — p[] 와 *(p + i) |
| 3 | 디자인패턴 | E17 | Bridge 와 Observer |
| 4 | DB | E10 | DB 설계 5단계 순서 |
| 5 | SW공학 | E16 | 비기능 요구사항 — 운영 · 자원 · 성능 |
| 6 | 네트워크 | E11 | HDLC 프레임 3종과 모드 2종 |
| 7 | 보안 | E13 | ISMS 인증 |
| 8 | C | E03 | 함수 포인터 멤버로 d + 1 — %x 출력 |
| 9 | SQL | E08 | COUNT(*) 와 COUNT(DISTINCT) |
| 10 | Python | E07 | [::-2] 역순 스텝과 end='A' |
| 11 | 네트워크 | E12 | /23 네트워크 주소 CIDR |
| 12 | Python | E07 | 얕은 복사 m[:] 와 안쪽 리스트 공유 |
| 13 | SQL | E08 | AVG 서브쿼리보다 큰 예산 조인 건수 |
| 14 | Python | E07 | split · join · 역순 · 글자 빼기 |
| 15 | 테스트 | E18 | 스텁과 드라이버 |
| 16 | 보안 | E14 | 워터링 홀 |
| 17 | Java | E06 | int + int + "2" + String 결합 순서 |
| 18 | SQL | E09 | FOREIGN KEY 제약 구문 빈칸 5개 |
| 19 | 보안 | E14 | 심볼릭 링크 공격 |
| 20 | SW공학 | E15 | 절차적 · 교환적 · 기능적 응집도 |
| 문항 | 왜 갈리나 |
|---|---|
| 1번 | g() 는 A 에 있고 f("a") 는 f(Object) 로 묶인다. 실행 때 B 의 f(Object) 가 골라져 2. f(String) 은 오버로딩이라 안 불린다 |
| 8번 | mine.fn(n) 은 n + 1 이라 32 를 가리킨다. %x 는 16진수라 20 |
| 12번 | b = m[:] 뒤 b[i + 1] += b[i] 는 안쪽 리스트를 제자리에서 늘린다. m 의 길이 합 1 + 2 + 3 + 4 = 10 |
| 17번 | 9 + 2 = 11 이 먼저, 그다음 "2" 가 붙어 문자열 112, 마지막 "3" → 1123 |
채점 결과는 오답노트에 회차별 점수와 틀린 문항 목록으로 모인다. 세트를 하나 끝낼 때마다 거기서 같은 장에서 반복해서 틀리는지를 본다. 두 세트에서 같은 장이 나오면 그 장의 06절 훈련을 그날 5문항 푼다.
왜 이걸 하나 — 세트의 결과는 다음에 열 장의 이름이어야 한다.