클라이언트 하드닝 기능 추가:
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- DevTools 감지 및 화면 삭제, 우클릭 차단 기능 구현
- PortalProperty 기반 설정 관리 서비스 추가
- 클라이언트 가드 스크립트 및 토글 로직 템플릿 연동
This commit is contained in:
Rinjae
2026-07-06 15:32:18 +09:00
parent b02e598d62
commit 83d267faed
13 changed files with 141 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,60 @@
/**
* client-guard.js
*
* 클라이언트측 하드닝. 서버가 내려준 window.__CLIENT_GUARD__ 플래그에 따라 각 기능을 독립 적용한다.
* - contextmenu: 우클릭(컨텍스트 메뉴) 차단
* - devtools : 창 크기 휴리스틱으로 DevTools 열림 감지 시 화면 전체 요소 영구 삭제
*
* 주의(한계): 창 크기 휴리스틱은 오탐/미탐이 있다(줌·북마크바·사이드패널·좁은창=오탐, undock 창=미탐).
* JS 비활성화·breakpoint·DOM 편집으로 우회 가능하므로 실질 보안이 아니라 억제용 데코이다.
*/
(function () {
'use strict';
var cfg = window.__CLIENT_GUARD__ || {};
// ── 우클릭(contextmenu) 차단 ─────────────────────────────────────────
if (cfg.contextmenu) {
document.addEventListener('contextmenu', function (e) {
e.preventDefault();
}, true);
}
// ── DevTools 감지 → 화면 영구 삭제 ───────────────────────────────────
if (cfg.devtools) {
var THRESHOLD = 160; // 도킹된 DevTools 패널이 차지하는 최소 폭/높이(px) 추정값
var POLL_MS = 500;
var wiped = false;
function isDevtoolsOpen() {
var widthGap = window.outerWidth - window.innerWidth;
var heightGap = window.outerHeight - window.innerHeight;
return widthGap > THRESHOLD || heightGap > THRESHOLD;
}
function wipe() {
if (wiped) {
return;
}
wiped = true;
// 화면 전체 요소 영구 삭제 (닫아도 복구되지 않음, 새로고침 필요)
try {
document.documentElement.replaceChildren();
} catch (ignore) {
if (document.body) {
document.body.innerHTML = '';
}
}
}
function check() {
if (!wiped && isDevtoolsOpen()) {
wipe();
}
}
window.setInterval(check, POLL_MS);
window.addEventListener('resize', check);
check();
}
})();