General

나이스지키미(credit.co.kr) 웹사이트 해부: 레거시 금융 플랫폼의 기술 스택


참고 안내 — 이 글은 외부에서 관찰 가능한 정보(DOM 구조, HTTP 응답, 공개 에셋 등)를 기반으로 작성된 개인적인 기술 분석이며, 학습과 참고 목적으로 제공됩니다. 내부 소스 코드에 직접 접근한 것이 아니므로 실제 구현 구조와 다를 수 있습니다. 분석 대상 사이트의 공식 입장과는 무관합니다.

📌 3줄 요약
  • XHTML 1.0 + jQuery 1.11.3(CVE 있음) 기반의 내부 MVC 프레임워크 ib20으로 구동되는 전형적인 국내 금융권 레거시 아키텍처다.
  • PC/모바일을 별도 도메인(www / m)과 URL 프리픽스(BZW / RZM)로 완전 분리한 구조이며, 캐시·압축·CSP 헤더가 모두 누락되어 squirrel audit 종합점수 41점(F)을 받았다.
  • TransKey 가상 키보드, ASTX2, KDFense 등 국내 금융 보안 솔루션 3종이 동시에 탑재되어 있어 웹 표준 중심의 현대적 보안 접근 방식과 대조된다.

첫인상: 나이스지키미를 처음 열었을 때

나이스지키미 메인 페이지

나이스지키미 메인 페이지 — 데스크톱 1440×900

사이트를 열면 신용점수, 소득그룹, 채무안정등급을 가로로 스와이프하는 정보 카드 세 장이 가장 먼저 눈에 들어온다. 로그인 전에는 점수 대신 ”?” 문자와 캐릭터 GIF로 채워져 있고, 로그인을 유도하는 구조다.

헤더는 로고 + GNB + 검색 아이콘으로 심플하게 구성되어 있으며, 우측 상단에 로그인/회원가입 링크가 따로 배치된다. 색상은 브랜드 블루(#066bfd)가 주요 인터랙션 요소에 일관되게 적용되어 있다.

로딩 시 눈에 띄는 지연이 있다. HTML 응답 후 JS가 순차 실행되면서 화면이 단계적으로 채워지는 패턴이 관찰된다 — <script> 태그가 35개 이상 동기 로딩되기 때문이다.

기술 스택 해부

프레임워크 & 아키텍처 패턴

나이스지키미는 ib20이라는 자체 MVC 프레임워크 위에서 동작한다. 이 이름은 URL 경로(/ib20/mnu/, /ib20/wgt/)와 action 파라미터에서 반복적으로 노출된다.

<input type="hidden" name="ib20_action" value="/ib20/wgt/RZMMANMNT01002VM">
<input type="hidden" name="ib20_cur_mnu" value="BZWMAN00001">
<input type="hidden" name="ib20_cur_wgt" value="RZMMANMNT01002VM">

메뉴 ID 네이밍 규칙이 체계적이다:

프리픽스의미
BZWPC 웹 (bizweb)
RZM모바일 웹 (모바일 전용)
CMN공통(Common)
MAN메인(Main)
MCLMy Credit

PC에서 특정 메뉴를 요청하면 서버가 302로 m.credit.co.kr 하위의 RZM 코드로 리다이렉트하는 방식이다. 즉, 반응형 CSS가 아닌 별도 도메인 분리 방식으로 PC/모바일 대응을 처리한다.

서버 사이드는 URL 패턴과 REQUEST_TOKEN_KEY 방식으로 보아 Java 기반(Spring 또는 자체 MVC)으로 추정된다.

프론트엔드 라이브러리 목록

HTML <head>에서 확인된 스크립트:

  • jQuery 1.11.3 — 메인 DOM 조작 라이브러리. CVE-2020-11022(XSS 취약점) 해당 버전.
  • jQuery UI — 달력, 셀렉트박스 등 UI 컴포넌트
  • Swiper.js — 메인 롤링 배너, 정보카드 슬라이더
  • Handlebars.js v4.7.6 — 클라이언트 사이드 템플릿 렌더링
  • Odometer.js — 숫자 카운트업 애니메이션
  • Modernizr 2.6.2 — 브라우저 feature detection (2014년 버전)
  • Lodash — 유틸리티 함수
  • in-view.min.js — 스크롤 뷰포트 감지

jQuery가 동일 페이지에 5회 중복 로딩되는 것이 squirrel audit에서 확인됐다. ext(확장 모듈)는 8회다. 레거시 시스템에서 여러 컴포넌트가 독립적으로 의존성을 포함한 결과다.

보안 솔루션 아키텍처

이 사이트의 가장 독특한 부분은 국내 금융 보안 솔루션을 겹겹이 탑재한 구조다:

TransKey (가상키보드)
  └── RSA OAEP 암호화
  └── JSBN (BigNumber 라이브러리)
  └── TypedArray 폴리필

ASTX2 (자동화 방지 / 봇 감지)
  └── astx2.min.js + astx2_jq.min.js

Kings KDFense (키로거 방지)
  └── kdfense_object.js

Wiselog (쿠키/동의 관리)
  └── makePCookie.js

TransKey는 입력 필드에 실제 키보드 대신 화면에 가상 키패드를 띄워 키로거를 무력화하는 솔루션이다. /transkeyServlet?op=getToken, getInitTime, getKeyboardHash 등 3개의 서블릿 호출이 페이지 로드 시 동기적으로 실행된다 — 렌더링 블로킹 요인이다.

프로젝트 구조 예측

추정 구조 — 외부 관찰 기반 역설계
graph TD
    ROOT["credit.co.kr (서버)"] --> CMN["cmn/ — 공통 JS/템플릿"]
    ROOT --> RESOURCE["resource/ — 정적 에셋"]
    ROOT --> IB20["/ib20/ — MVC 라우팅 엔트리"]

    CMN --> JS_CMN["js/include/zkm/rzm/ — 공통 유틸"]
    CMN --> EXT["ext/ — jQuery 확장 모듈"]

    RESOURCE --> JS_RES["js/zkm/rzm/ — 페이지별 JS"]
    RESOURCE --> CSS["css/zkm/rzm/ — 스타일시트"]
    RESOURCE --> IMG["img/zkm/rzm/ — 이미지 에셋"]
    RESOURCE --> PRODUCT["product/ — 보안솔루션 번들"]

    IB20 --> MNU["/mnu/{MENU_ID} — 메뉴 라우트"]
    IB20 --> WGT["/wgt/{WIDGET_ID} — 위젯 액션"]

    PRODUCT --> TRANSKEY["transkey/ — 가상키보드"]
    PRODUCT --> ASTX2["astx/astx2/ — 자동화방지"]
    PRODUCT --> KINGS["kings/ — 키로거방지"]

    style ROOT fill:#3b82f6,stroke:#2563eb,color:#fff
    style IB20 fill:#8b5cf6,stroke:#7c3aed,color:#fff
    style PRODUCT fill:#ef4444,stroke:#dc2626,color:#fff

디자인 시스템 분석

컬러 팔레트

CSS 파일에서 추출한 주요 컬러:

#066bfdPrimary / pColor
#d50f3cSecondary / sColor (위험/경고)
#222222기본 텍스트
#767676보조 텍스트 / gColor
#f0f0f0배경 / bgGray
#eaf1ff연한 파란 배경 / bgblue

CSS 변수(--color-*) 체계는 사용하지 않는다. 색상값이 클래스명에 하드코딩되어 있으며, 다크모드 지원도 없다. 색상 관리는 .pColor, .sColor, .gColor 같은 유틸리티 클래스 방식이다.

타이포그래피

폰트 파일은 img.credit.co.kr/resource/css/zkm/rzm/font.css에서 별도 서빙된다. CSS에서 font-size: 16px, font-weight: 600.largeTxt 클래스가 강조에 사용되고, 기본 본문은 400 weight다.

font-weight 클래스를 utility로 제공한다: .bold, .thick(700), .medium(500), .light(400). 한국어 콘텐츠 특성상 기본 weight가 낮으면 가독성에 불리하지만, 전체적으로 weight 계층이 명확히 정의되어 있다.

레이아웃 & 반응형

데스크톱 풀페이지

데스크톱 풀페이지 레이아웃

모바일 뷰

모바일 뷰 — 390×844 above-the-fold

반응형 대응 방식이 현대 사이트와 근본적으로 다르다. CSS 미디어 쿼리로 같은 DOM을 재배치하는 게 아니라, 서버에서 User-Agent를 감지하여 PC면 www.credit.co.kr, 모바일이면 m.credit.co.kr로 302 리다이렉트한다.

CSS 코드에서도 이 구조가 그대로 드러난다:

.mobile .mbHide,
.pweb .pcHide { display: none !important; }

html 태그에 .pweb 또는 .mobile 클래스를 JS로 붙이고, 이 클래스 기반으로 PC/모바일 전용 요소를 토글한다. 미디어 쿼리 breakpoint는 max-width: 280px 하나뿐으로, 반응형이 아닌 ‘조건부 숨김’ 방식이다.

데스크톱 레이아웃은 중앙 정렬 컨테이너 구조이며, 메인 콘텐츠 영역은 최대 너비가 설정된 innerWrap 클래스로 감싸진다.

UX 패턴 깊이 파기

네비게이션

GNB는 신용, 자산, 금융진단, 라이프, 관리/설정, 고객센터 6개 카테고리로 구성된다. 메뉴 아이템은 onclick="goMenuWithAuth('BZWMCLMNG10')" 패턴으로 전부 JavaScript 이벤트 핸들러에 연결되어 있어, href에 실제 URL이 없다.

<!-- 실제 메뉴 링크 패턴 -->
<a href="#void" onclick="goMenuWithAuth('BZWMCLMNG10')">내 신용점수</a>
<a href="#void" onclick="goMenuWithAuth('BZWMCLMCU10')">신용점수 올리기</a>

이 패턴은 SEO에 치명적이다. 크롤러가 링크를 따라가도 #void이므로 사이트 내부 링크 구조를 인식할 수 없다. squirrel audit에서 “internal links: 0”으로 집계된 이유다.

신규/인기 메뉴에는 .sticker.new, .sticker.hot 클래스로 뱃지를 표시한다. PNG 스프라이트 방식으로 구현되어 있다.

인터랙션 & 애니메이션

메인의 이벤트 카드 섹션(.mainEventSwiper)은 PC에서 2초마다 각 카드에 .hover 클래스를 순차적으로 추가하여 자동 하이라이트 효과를 만든다. 사용자가 hover/focus 중인 요소는 건너뛰는 접근성 배려가 코드에 명시되어 있다(// s: 2026 접근성심사 주석).

Odometer.js를 이용한 숫자 카운트업 효과가 신용점수 표시에 적용된다. 로그인 상태에서는 실제 점수가 롤링되며 표시될 것으로 보인다.

GIF 애니메이션이 3개 사용 중이다(img_zikisae_question.gif, img_coin.gif, bg_store_main.gif). 현대 사이트라면 WebP나 CSS 애니메이션으로 대체했을 부분이다.

정보 구조

메인 콘텐츠는 크게 세 레이어로 구성된다:

  1. 사용자 개인화 영역 — 신용점수/소득/채무안정등급 카드 (로그인 전: ?, 로그인 후: 실제값)
  2. 롤링 광고 배너 — Swiper.js 기반, 5초 자동전환
  3. 서비스 소개 섹션 — 주요 기능 카드형 진입점

금융진단(대출가능진단, 카드발급진단, 보험혜택진단), 라이프(이름어때, 상권분석), 이벤트 섹션이 하단에 이어진다.

SEO & 웹 표준

squirrel audit 결과 요약

카테고리점수
전체 종합41 (F)
접근성83
URL 구조88
크롤러빌리티76
보안76
링크76
Core SEO70
콘텐츠69
모바일67
성능64
E-E-A-T62
이미지60
법적 컴플라이언스44

주요 이슈 정리

보안 헤더 전무:

  • Content-Security-Policy 없음
  • Strict-Transport-Security 없음
  • X-Frame-Options 없음 (클릭재킹 무방비)

외부에서 관찰 가능한 보안 헤더가 없다는 건 의외다. TransKey/ASTX2 같은 클라이언트 레이어 보안에 집중하면서, 표준 HTTP 보안 헤더 쪽은 상대적으로 소홀한 모습이다.

인코딩:

<meta http-equiv="Content-Type" content="text/html;charset=euc-kr">

2026년에도 EUC-KR을 사용하는 국내 금융 서비스를 종종 볼 수 있다. 레거시 DB/서버 시스템과의 인코딩 통일을 위한 선택이지만, 국제화 대응이나 일부 브라우저 환경에서 깨짐 리스크가 있다. squirrel audit에서도 경고로 집계됐다.

DOCTYPE:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...>

HTML5가 아닌 XHTML 1.0 Transitional을 사용한다. 이 doctype은 2000년대 초반 웹 표준화 운동의 산물이다. 렌더링 자체에는 큰 영향이 없지만, 시스템이 얼마나 오래된 기반 위에 있는지 보여주는 단서다.

성능:

  • HTTP 압축(gzip/br) 미적용 — 73KB HTML이 그대로 전송
  • 캐시 헤더 없음 (no-cache, no-store, must-revalidate)
  • 렌더 블로킹 CSS 5개 + 동기 JS 35개 이상
  • jQuery v1.11.3 중복 5회 로딩 (CVE-2020-11022)

배울 점 & 아쉬운 점

참조할 만한 기술

1. 접근성 투자

접근성 점수(83)가 다른 항목 대비 높은 편이다. Swiper 슬라이더에 aria-hidden, aria-label, tabindex, role="button"이 체계적으로 붙어 있고, “2026 접근성심사” 주석과 함께 포커스 상태 처리 코드가 최근 추가됐다:

// s: 2026 접근성심사
const hoverOrFocusedElements = new Set()
$ele.on('mouseenter focusin', function(){
    hoverOrFocusedElements.add(this);
}).on('mouseleave focusout', function(){
    hoverOrFocusedElements.delete(this);
})
// e: 2026 접근성심사

자동 롤링 애니메이션이 포커스 중인 요소를 건너뛰는 패턴은 실무에서 참고할 만하다.

2. 보안 솔루션 통합 패턴

TransKey 가상 키보드는 실제 키보드 이벤트를 서버로 전송하지 않고 RSA OAEP로 암호화된 값만 전송한다. 금융 서비스에서 비밀번호 입력 보안을 어떻게 처리하는지 보여주는 실제 사례다. 오픈소스 대안으로는 react-virtual-keyboard 등이 있다.

3. 메뉴 ID 네이밍 체계

BZW, RZM 프리픽스 + 도메인 코드(MCL, BMO 등) + 기능 코드 조합의 계층적 ID 체계는 수백 개의 메뉴가 있는 대형 금융 서비스에서 관리 복잡도를 낮추는 방법이다.

개선 여지

  • jQuery 1.11.3 업그레이드 필요: CVE-2020-11022 XSS 취약점이 있는 버전이다. jQuery 3.x로 올리거나, 장기적으로 Vanilla JS / 현대 프레임워크로 마이그레이션이 필요하다.
  • HTTP 압축 미적용: gzip/Brotli 압축만 켜도 HTML 크기를 70 ~ 80% 줄일 수 있다. 가장 빠른 성능 개선 포인트다.
  • href="#void" 링크 구조: SEO/접근성 모두에 불리하다. href에 실제 URL을 넣고 JS로 인터셉트하는 방식이 표준적이다.
  • PC/모바일 별도 도메인: m.credit.co.kr로 리다이렉트하는 구조는 canonical URL 관리, SEO 중복 콘텐츠 이슈를 만든다.
  • EUC-KR → UTF-8 전환: 레거시 DB와의 연동이 이유겠지만, 장기적으로 UTF-8 통일이 필요하다.

배울 점: 개발자가 가져갈 기술적 인사이트

1. 레거시 시스템에서 접근성 개선하는 법

전체 아키텍처를 바꾸지 않고도 접근성을 개선할 수 있다. aria-* 속성 추가, tabindex 관리, Set을 이용한 포커스 추적 등은 기존 jQuery 코드 위에 그대로 얹을 수 있다. 나이스지키미의 2026 접근성 심사 대응 코드가 그 실증이다.

2. 국내 금융 보안의 현실

TransKey, ASTX2, KDFense는 금융감독원의 전자금융 보안 가이드라인을 충족하기 위한 국내 표준 솔루션이다. 이런 솔루션들이 렌더 블로킹을 유발하는 건 성능과 규제 준수 사이의 트레이드오프다. 핀테크 스타트업이 이 규제를 어떻게 현대적으로 풀어나가는지 비교해보면 흥미롭다.

3. HTTP 캐시 전략의 중요성

no-cache, no-store로 모든 캐시를 비활성화한 설정은 금융 데이터의 신선도를 보장하기 위한 의도적 선택이다. 하지만 정적 에셋(CSS, JS, 이미지)까지 캐시를 끄는 건 과도하다. 버전 쿼리(?v=2202603031538)를 붙이는 캐시 버스팅 패턴을 쓰고 있으므로, 정적 에셋에는 Cache-Control: max-age=31536000, immutable을 적용해도 안전하다.

자주 묻는 질문 (FAQ)

Q1. 왜 React나 Vue 같은 현대 프레임워크 대신 jQuery를 사용할까요?

금융 서비스의 프론트엔드 교체는 단순한 기술 결정이 아니다. TransKey, ASTX2 같은 보안 솔루션들이 jQuery 기반으로 제공되는 경우가 많고, 전자금융 보안 인증 재취득 비용, 수백 개 화면의 QA, 레거시 서버와의 통신 방식 등 모든 것이 얽혀 있다. 새로 만드는 서비스라면 다른 선택을 하겠지만, 기존 서비스의 전환 비용은 기술적 판단 이상의 문제다.

Q2. PC와 모바일을 별도 도메인으로 분리한 이유는 무엇인가요?

반응형 웹 디자인이 업계 표준이 되기 전(2012년 이전)에 구축된 서비스들은 대부분 이 방식을 택했다. m. 서브도메인에 완전히 별도 템플릿을 유지하는 건 초기에는 간단한 접근이었지만, 이후 운영 비용이 두 배로 늘어나는 구조다. 나이스지키미처럼 BZW/RZM 프리픽스 체계가 잡혀 있으면 서버에서 라우팅을 일관되게 관리할 수 있다는 장점은 있다.

Q3. Handlebars.js를 클라이언트 사이드에서 사용하는 이유는 무엇인가요?

서버에서 HTML을 완전히 렌더링해서 내려주는 방식과 클라이언트에서 JSON 데이터를 받아 Handlebars 템플릿으로 렌더링하는 방식을 혼용하는 것으로 보인다. 사용자 개인화 데이터(신용점수 등)는 로그인 후 API 호출로 받아서 클라이언트에서 렌더링하는 편이 초기 HTML 캐싱에 유리하다. Handlebars는 로직 없는(logicless) 템플릿 철학으로 XSS 방어가 기본 내장되어 있어 금융 서비스에서 선호된다.

참고 안내 — 이 글은 외부에서 관찰 가능한 정보(DOM 구조, HTTP 응답, 공개 에셋 등)를 기반으로 작성된 개인적인 기술 분석이며, 학습과 참고 목적으로 제공됩니다. 내부 소스 코드에 직접 접근한 것이 아니므로 실제 구현 구조와 다를 수 있습니다. 분석 대상 사이트의 공식 입장과는 무관합니다.