본 글은 보안 스터디 및 모의해킹 실습을 목적으로 작성되었습니다. 모든 테스트는 직접 제작하거나 허가받은 환경에서만 진행했습니다.
1. 점검 개요
웹 애플리케이션을 대상으로 Black-Box와 White-Box 방식의 보안 점검을 진행했다.
- Black-Box: HTTP 요청 및 응답을 이용한 동적 점검
- White-Box: PHP 및 SQL 소스코드 분석
점검 결과 주요 취약점으로는 SQL Injection, IDOR, Stored XSS가 확인되었다.
2. 점검 결과
| 취약점 | 위치 | 위험도 | 확인 방식 |
|---|---|---|---|
| SQL Injection | 모델 검색 | High | Black-Box + White-Box |
| Stored XSS | 댓글 출력 | High | White-Box |
| IDOR | 프로필 수정 | Medium | Black-Box + White-Box |
3. SQL Injection
원인
모델 검색 기능에서 사용자 입력값을 SQL 문자열에 직접 연결하고 있었다.
$sql = "SELECT * FROM models
WHERE name LIKE '%$q%'
OR summary LIKE '%$q%'
ORDER BY downloads DESC";
$models = db()->query($sql)->fetchAll();
사용자 입력과 SQL 명령이 분리되지 않아 SQL Injection이 발생할 수 있다.
영향
점검 과정에서 검색 조건을 조작하고 UNION 결과를 화면에 출력할 수 있음을 확인했다. 민감한 사용자 정보는 조회하지 않았으며, DB 버전 정보만 확인에 사용했다.
대응
Prepared Statement를 사용하여 SQL과 사용자 입력을 분리한다.
$like = "%$q%";
$stmt = db()->prepare(
'SELECT * FROM models
WHERE name LIKE ?
OR summary LIKE ?
OR tags LIKE ?'
);
$stmt->execute([$like, $like, $like]);
4. IDOR
원인
프로필 수정 기능이 서버 세션의 사용자 ID가 아니라 요청으로 전달된 user_id를 수정 대상에 사용했다.
$targetId = isset($_POST['user_id'])
? (int)$_POST['user_id']
: (int)$me['id'];
로그인 여부는 확인하지만 해당 사용자가 대상 프로필을 수정할 권한이 있는지는 확인하지 않는다.
영향
직접 생성한 두 개의 테스트 계정으로 확인한 결과, 한 계정에서 다른 테스트 계정의 프로필 정보를 변경할 수 있었다.
대응
수정 대상은 클라이언트 입력이 아닌 로그인 세션에서 가져온다.
$me = require_login();
$userId = (int)$me['id'];
$stmt = db()->prepare(
'UPDATE users
SET display_name=?, bio=?, email=?
WHERE id=?'
);
$stmt->execute([
$display,
$bio,
$email,
$userId
]);
5. Stored XSS
원인
댓글은 정상적으로 DB에 저장되지만, 출력할 때 HTML 이스케이프가 적용되지 않는 코드 경로가 존재했다.
<?=$c['content']?>
사용자 입력이 그대로 HTML로 출력되면 브라우저가 이를 태그 또는 JavaScript로 해석할 수 있다.
영향
게시글을 열람한 사용자의 브라우저에서 스크립트가 실행될 가능성이 있다. 관리자가 해당 페이지를 열람할 경우 관리자 권한이 적용된 요청에도 영향을 줄 수 있다.
대응
댓글 출력 시 HTML 이스케이프를 적용한다.
<?=nl2br(e($c['content']))?>
9. 결론
점검 결과 주요 취약점은 다음과 같다.
| 취약점 | 위험도 |
|---|---|
| SQL Injection | High |
| Stored XSS | High |
| IDOR | Medium |
Disclaimer 본 글의 모든 보안 테스트는 교육 및 연구 목적으로 허가된 환경에서만 수행되었습니다.
