// 이 파일이 하는 일: "앱 보안과 권한" 코스 — 앱 보안이 웹과 무엇이 다른지에서
// 출발해, 권한 모델·저장소 보안·통신 보안·스토어 심사·흔한 취약점을 거쳐, 결국
// 우리 학습 플랫폼(React + Spring Boot)이 이미 지키는 원칙과 만나는 흐름으로
// 7개 섹션을 안내하는 정적 학습 페이지다. 목표는 "2개월에 앱 보안 전문가"가 아니라
// "웹에서 익힌 보안 감각을 다리 삼아, 앱에서 무엇이 달라지는지 지형을 읽는" 수준.
// 학습 포인트: API 호출이 없는 '내용 고정' 페이지다. 스타일은 global.css의
// 가이드 전용 클래스(step-card, code-block, tip 등)를 재사용한다 — 색은 여기서
// 하드코딩하지 않고 var(--primary/--teal/--amber/--ink/--line/--card/--muted/--rose)만 쓴다.
// 예제 코드는 JSX 중괄호/백틱 충돌을 피하려고 파일 상단의 백틱 문자열 상수로 정의한다.

import { Link } from 'react-router-dom';

// ── 예제 코드 상수들 ──

const CODE_TRUST = `보안에서 가장 중요한 질문 하나:  "코드가 누구 손에 있나?"

웹                                     앱
──────────────────────────────       ──────────────────────────────
접속할 때마다 우리 서버가                한 번 설치하면 앱 파일(APK/IPA)이
화면 코드를 '새로' 내려 준다.            사용자 기기 안에 '남는다'.
민감한 로직·비밀은 서버에.               그 파일은 다운로드·디컴파일·변조 가능.

비유: 웹은 식당에서 그때그때             비유: 앱은 레시피 카드를 인쇄해
차려 내오는 요리(접시는 회수).           나눠 주는 것. 한 번 나가면 누구나
                                       한 줄씩 읽고, 복사하고, 고쳐 본다.

→ 그래서 앱 보안의 제1원칙:  "클라이언트(앱)는 이미 공격자 손 안에 있다."
   앱 안에 넣은 비밀은 비밀이 아니다. 진짜 검사는 언제나 서버가 다시 한다.`;

const CODE_PERMISSION = `// 안드로이드 — AndroidManifest.xml 에 '필요한 권한'을 선언한다
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

// iOS — Info.plist 에 '왜 필요한지'를 사람 말로 적어야 한다(안 적으면 크래시/거부)
<key>NSCameraUsageDescription</key>
<string>과제 사진을 찍어 제출하기 위해 카메라를 사용합니다</string>

// 위험 권한(카메라·위치·연락처·마이크)은 '설치 때 몰아서'가 아니라
// 실제로 쓰는 그 순간, 사용자에게 팝업으로 물어본다 — 런타임 권한.
//     [허용]   [앱 사용 중에만]   [이번만]   [거부]     ← 거부할 수 있다!
//
// 그래서 코드는 언제나 "거부당했을 때"를 대비해야 한다.
if (!granted) {
  showMessage("카메라 없이도 과제는 파일 업로드로 낼 수 있어요");  // 우아한 대비책
}`;

const CODE_STORAGE = `// ❌ 평문 저장 — 절대 금지
//    안드로이드 SharedPreferences / iOS UserDefaults 에 토큰을 '그냥' 저장하면
//    루팅/탈옥된 기기나 백업 파일에서 통째로 읽힌다.
prefs.putString("authToken", token);   // 열쇠를 현관 매트 밑에 두는 격

// ✅ OS가 제공하는 '금고'에 맡긴다
//    iOS        : Keychain      (Secure Enclave 하드웨어에 보관)
//    안드로이드   : Keystore / EncryptedSharedPreferences (TEE 하드웨어에 보관)
//    앱조차 키 원본을 직접 못 보고, "이걸로 암호화/복호화만 해 줘"라고 OS에 부탁한다.

// 그리고 — 서버 비밀(API 시크릿·DB 비밀번호)은 앱에 절대 넣지 않는다.
//    앱 바이너리는 디컴파일되면 문자열이 다 드러난다. 비밀은 오직 서버에.`;

const CODE_TLS = `일반 HTTPS(TLS)                     인증서 고정(Certificate Pinning)
──────────────────────────        ──────────────────────────────────
"공인기관(CA)이 서명한                "나는 '우리 서버의 바로 그 인증서'만
 인증서면 믿는다"                      믿는다" — 지문을 앱에 미리 새겨 둠
→ 공용 와이파이 도청은 막는다           → 가짜 CA·중간자(MITM) 공격까지 막는다

// 함정: 서버 인증서를 갱신하면 앱도 같이 업데이트해야 한다.
//       안 그러면 정상 서버인데도 통신이 끊긴다(핀 불일치). 그래서 신중히.

// 요즘 OS는 기본적으로 평문 http:// 를 막는다:
//   iOS        : App Transport Security(ATS) — HTTPS 강제
//   안드로이드   : 기본 cleartext 차단(usesCleartextTraffic=false)`;

const CODE_REVIEW = `스토어 심사 — 보안·개인정보 관련 단골 체크 항목
──────────────────────────────────────────────
□ 권한 정당화     신청한 권한을 '실제로' 그 용도로만 쓰는가?
                 (배경 위치·SMS·연락처·통화기록은 특히 깐깐하게 본다)
□ 데이터 안전     무슨 데이터를 왜 모으는지 신고
                 (Google Play '데이터 보안' / Apple '앱 개인정보 보호' 라벨)
□ 개인정보처리방침  공개된 URL 필수
□ 통신 암호화     HTTPS 사용(Apple ATS), 평문 전송 금지
□ 악성·기만 없음   숨은 기능·과도한 추적·다운로드형 코드 실행 금지

// 거부되면 사유가 온다 → 고쳐서 재심사(며칠 걸릴 수 있음).
// 웹 배포처럼 '푸시하면 바로 반영'이 아니다 — 이 리듬 차이를 미리 알아 두자.`;

const CODE_VULN = `입문자가 가장 자주 만드는 앱 취약점 5가지
──────────────────────────────────────────
1) 평문 저장        토큰·비밀번호를 그냥 저장            → 섹션 3
2) 하드코딩된 비밀   API 키를 앱 코드에 박아 둠(디컴파일로 유출)  → 섹션 3
3) 통신 미암호화     http:// 로 그냥 쏨(도청·변조)         → 섹션 4
4) 과잉 권한        안 쓰는 카메라·위치까지 요청(신뢰·심사 감점) → 섹션 2
5) 클라이언트 과신   "관리자만" 판정을 앱 화면에서만 함        → 섹션 1

★ 다섯 개를 관통하는 한 줄:  "클라이언트를 믿지 마라"
   설치된 앱은 공격자 손 안에 있다. 화면(메뉴·버튼)을 숨기는 건 UX일 뿐,
   진짜 권한 검사·금액 계산·본인 확인은 반드시 서버가 다시 한다.`;

const CODE_OURS = `앱 세계의 수칙          우리 플랫폼이 이미 하는 것 (React + Spring Boot)
────────────────────  ────────────────────────────────────────────────
최소 권한             RequireAuth·RequireMentor 가드로 '필요한 사람만' 통과.
                     방화벽 코스: AWS 보안그룹은 필요한 포트만 연다.
비밀은 평문 금지        비밀번호는 서버에서 BCrypt로 해싱해 저장 — 원문은 없다.
서버가 최종 심판        App.jsx 주석 그대로:
                     "프론트 가드는 UX용 안내, 진짜 보안은 서버(API)가 담당."
통신은 HTTPS          로그인은 비밀번호를 실어 보낸다 → 전 구간 HTTPS가 전제.
                     (네트워크·HTTP 코스에서 배운 TLS·인증서가 그 바탕)
로그인 상태 확인        토큰을 화면이 들고 다니지 않고 서버에 물어 확인
                     (GET /api/auth/me). 앱이라면 토큰을 Keychain/Keystore에.`;

// ── 이 페이지 안에서만 쓰는 작은 부품들 ──
// 학습 포인트: 같은 모양이 반복되면 컴포넌트로 뽑는다. props(n·title·sub)만 바꿔 재사용.
function Section({ n, title, sub, children }) {
  return (
    <section className="step-card" id={`sec-${n}`}>
      <div className="step-head">
        <span className="step-num">{n}</span>
        <div>
          <h3>{title}</h3>
          {sub && <span className="step-sub">{sub}</span>}
        </div>
      </div>
      <div className="step-body">{children}</div>
    </section>
  );
}

function Code({ children }) {
  return <pre className="code-block"><code>{children}</code></pre>;
}

const SECTIONS = [
  { n: 1, label: '웹과 다른 점' },
  { n: 2, label: '권한 모델' },
  { n: 3, label: '민감정보 저장' },
  { n: 4, label: '통신 보안' },
  { n: 5, label: '스토어 심사' },
  { n: 6, label: '흔한 취약점' },
  { n: 7, label: '우리 플랫폼과 공통점' },
];

export default function AppSecurityPage() {
  return (
    <div>
      {/* 히어로: 웹 보안 감각을 다리 삼아 앱 보안의 지형으로 */}
      <div className="hero">
        <div className="eyebrow">Course · 앱 개발</div>
        <h1>앱 보안과 권한<br />— 웹과 무엇이 다른가</h1>
        <p>
          앱 보안의 원리는 웹과 뿌리가 같아요. 다른 건 딱 하나 —{' '}
          <strong>코드가 사용자(그리고 공격자)의 기기 안에 설치돼 남는다</strong>는 점입니다.
          이 한 가지 차이에서 권한 모델·저장소 보안·통신 보안·스토어 심사가 전부 갈라져 나와요.
          여러분이 이미 배운 방화벽의 최소 권한, HTTP의 TLS, 우리 서버의 해싱을{' '}
          <strong>다리 삼아</strong> 앱 보안의 지형을 읽어 봅니다.
        </p>
        <div className="chip-row">
          <span className="chip">예상 소요 75분</span>
          <span className="chip">실습: 우리 SecurityConfig·App.jsx 가드 읽기</span>
          <span className="chip">선수 지식: 방화벽·HTTP 코스</span>
        </div>
      </div>

      {/* 섹션 바로가기 */}
      <nav className="pill-nav">
        {SECTIONS.map((s) => (
          <a key={s.n} href={`#sec-${s.n}`}>
            <b>{s.n}</b>
            {s.label}
          </a>
        ))}
      </nav>

      <Section n={1} title="앱 보안이 웹과 다른 점" sub="핵심 질문: 코드가 누구 손에 있나?">
        <p>
          웹 페이지는 접속할 때마다 우리 서버가 화면 코드를 <strong>새로 내려 줍니다.</strong>{' '}
          민감한 로직과 비밀은 서버에 두고, 브라우저에는 그때그때 필요한 조각만 보내죠.
          브라우저는 그 코드를 <strong>샌드박스</strong>라는 격리된 방 안에서만 실행하고요.
        </p>
        <p>
          앱은 다릅니다. 한 번 설치하면 앱 파일(<span className="icode">APK</span>·
          <span className="icode">IPA</span>)이 사용자 기기 안에 <strong>남아요.</strong> 그리고
          그 파일은 다운로드·디컴파일(역분석)·변조가 가능합니다. 즉 <strong>여러분이 앱에 넣은
          모든 것 — API 키, 숨긴 화면, 검사 로직 — 이 잠재적으로 공격자 손에 있다</strong>는
          뜻이에요.
        </p>
        <Code>{CODE_TRUST}</Code>
        <svg className="diagram" viewBox="0 0 640 340" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="신뢰 경계 그림: 웹은 우리 서버가 매번 화면 코드를 내려 주고 브라우저 샌드박스만 사용자 기기에 있지만, 앱은 앱 바이너리 전체가 사용자와 공격자의 기기에 설치되어 남아 뜯어보고 복제할 수 있다">
          <line x1="330" y1="64" x2="330" y2="316" stroke="var(--amber)" strokeWidth="2" strokeDasharray="5 4" />
          <text x="330" y="52" textAnchor="middle" fontSize="13" fontWeight="600" fill="var(--amber)">신뢰 경계</text>
          <text x="175" y="52" textAnchor="middle" fontSize="12" fill="var(--muted)">우리가 통제 · 서버</text>
          <text x="490" y="52" textAnchor="middle" fontSize="12" fill="var(--muted)">사용자 · 공격자의 기기</text>

          <text x="28" y="126" textAnchor="start" fontSize="14" fontWeight="600" fill="var(--ink)">웹</text>
          <rect x="70" y="96" width="150" height="52" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="145" y="118" textAnchor="middle" fontSize="13" fill="var(--ink)">우리 서버</text>
          <text x="145" y="136" textAnchor="middle" fontSize="11" fill="var(--muted)">코드·비밀 전부</text>
          <line x1="220" y1="122" x2="392" y2="122" stroke="var(--primary)" strokeWidth="2" />
          <path d="M400 122 L390 117 L390 127 Z" fill="var(--primary)" />
          <text x="306" y="112" textAnchor="middle" fontSize="11" fill="var(--primary)">HTTPS로 조각만</text>
          <rect x="400" y="96" width="170" height="52" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="2" />
          <text x="485" y="118" textAnchor="middle" fontSize="13" fill="var(--ink)">브라우저 탭</text>
          <text x="485" y="136" textAnchor="middle" fontSize="11" fill="var(--muted)">샌드박스 · 매번 새로</text>

          <text x="28" y="236" textAnchor="start" fontSize="14" fontWeight="600" fill="var(--ink)">앱</text>
          <rect x="70" y="206" width="150" height="52" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="145" y="228" textAnchor="middle" fontSize="13" fill="var(--ink)">우리 서버</text>
          <text x="145" y="246" textAnchor="middle" fontSize="11" fill="var(--muted)">API만 제공</text>
          <line x1="220" y1="232" x2="392" y2="232" stroke="var(--primary)" strokeWidth="2" />
          <path d="M400 232 L390 227 L390 237 Z" fill="var(--primary)" />
          <text x="306" y="222" textAnchor="middle" fontSize="11" fill="var(--primary)">HTTPS</text>
          <rect x="400" y="206" width="170" height="52" rx="8" fill="var(--card)" stroke="var(--rose)" strokeWidth="2" />
          <text x="485" y="228" textAnchor="middle" fontSize="13" fill="var(--ink)">앱 바이너리</text>
          <text x="485" y="246" textAnchor="middle" fontSize="11" fill="var(--muted)">기기에 설치 · 상주</text>
          <text x="485" y="288" textAnchor="middle" fontSize="12" fill="var(--rose)">APK/IPA = 뜯어보고 복제 가능</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: 신뢰 경계 — 웹은 브라우저 샌드박스만 경계 밖에 있지만, 앱은 바이너리 전체가 공격자 영역에 상주한다</p>
        <div className="warn">
          <b>가장 흔한 착각</b> "앱에 넣었으니 사용자는 못 보겠지"는 틀렸어요. 앱은 뜯어볼 수
          있으니 <strong>앱 안의 비밀은 비밀이 아닙니다.</strong> 그래서 앱 보안의 제1원칙은
          "클라이언트를 믿지 마라" — 진짜 검사는 항상 서버가 다시 합니다. 우리 플랫폼도
          똑같아서, <span className="icode">App.jsx</span>의 라우팅 가드는{' '}
          <strong>화면 안내(UX)</strong>일 뿐이고 진짜 권한 판정은 서버(API)가 해요.
        </div>
      </Section>

      <Section n={2} title="권한 모델" sub="카메라·위치… 최소 권한은 방화벽에서 배운 그 원칙">
        <p>
          웹에서도 위치·카메라를 쓰려면 브라우저가 팝업으로 물어봤죠(
          <span className="icode">getUserMedia</span>·위치 권한). 앱은 이걸{' '}
          <strong>훨씬 넓게, OS 차원에서</strong> 합니다. 앱은 필요한 권한을 먼저{' '}
          <strong>선언</strong>하고(안드로이드 <span className="icode">AndroidManifest.xml</span>,
          iOS <span className="icode">Info.plist</span>), 카메라·위치·연락처 같은{' '}
          <strong>위험 권한</strong>은 실제로 쓰는 순간 사용자에게 다시 물어봐요(런타임 권한).
        </p>
        <Code>{CODE_PERMISSION}</Code>
        <p>
          여기서 방화벽 코스의 <strong>최소 권한(least privilege)</strong>이 그대로 돌아옵니다.
          AWS 보안그룹에서 <strong>필요한 포트만</strong> 열었던 것처럼, 앱도{' '}
          <strong>기능이 실제로 필요로 하는 권한만</strong> 요청해야 해요. "언젠가 쓸지도
          몰라서" 권한을 미리 몰아 받는 건 사용자 불신 + 스토어 감점의 지름길입니다.
          그리고 사용자가 <strong>거부할 수 있다</strong>는 전제로, 거부 시의 대비책까지
          코드에 넣어야 하고요.
        </p>
        <div className="tip">
          <b>연결해서 보기</b> 이 "필요한 것만 연다"는{' '}
          <Link to="/learn/firewall"><strong>방화벽과 보안 기초</strong></Link> 코스의 핵심과
          똑같아요. 포트든 앱 권한이든 데이터베이스 계정이든 — <strong>줄 수 있는 최소한만
          준다</strong>가 보안의 뼈대입니다. 권한을 하나 요청할 때마다 "이게 이 화면에 정말
          필요한가?"를 스스로 물어보세요.
        </div>
      </Section>

      <Section n={3} title="민감정보 저장" sub="키체인/키스토어 vs 평문 — 열쇠를 어디에 둘까">
        <p>
          앱은 로그인 토큰이나 설정을 기기에 저장할 때가 많아요. 문제는{' '}
          <strong>어디에, 어떻게</strong> 저장하느냐입니다. 안드로이드의{' '}
          <span className="icode">SharedPreferences</span>나 iOS의{' '}
          <span className="icode">UserDefaults</span>에 토큰을 <strong>평문으로 그냥</strong>{' '}
          넣으면, 루팅·탈옥된 기기나 백업 파일에서 통째로 읽힙니다. 열쇠를 현관 매트 밑에 두는
          셈이에요.
        </p>
        <Code>{CODE_STORAGE}</Code>
        <p>
          그래서 OS는 <strong>하드웨어로 보호되는 금고</strong>를 제공합니다. iOS의{' '}
          <strong>Keychain</strong>(Secure Enclave), 안드로이드의 <strong>Keystore</strong>
          (TEE)죠. 앱조차 키 원본을 직접 보지 못하고 "이걸로 암호화/복호화만 해 줘"라고 OS에
          부탁만 해요. 그리고 <strong>API 시크릿·DB 비밀번호 같은 서버의 비밀은 앱에 넣지
          않습니다</strong> — 디컴파일하면 문자열이 다 보이니까요. 비밀은 오직 서버에.
        </p>
        <div className="tip">
          <b>우리 서버가 하는 것과 같은 결</b> 우리 백엔드는 비밀번호를{' '}
          <strong>절대 평문으로 저장하지 않고</strong> BCrypt로 해싱해서 넣어요(
          <span className="icode">SecurityConfig.java</span>의{' '}
          <span className="icode">BCryptPasswordEncoder</span>). "민감한 값은 읽을 수 있는
          형태로 두지 않는다"는 원칙은 서버의 해싱이든 앱의 키스토어든 완전히 똑같습니다.
        </div>
      </Section>

      <Section n={4} title="통신 보안" sub="HTTPS는 기본, 인증서 고정은 한 겹 더">
        <p>
          기기와 서버 사이를 오가는 데이터는 <strong>암호화</strong>돼야 해요. 여기까진 웹과
          완전히 같습니다 — HTTP 코스에서 배운 <strong>HTTPS(TLS)</strong>가 공용 와이파이의
          도청을 막죠. 다행히 요즘 OS는 <strong>기본적으로 평문 http:// 를 막습니다</strong>
          (iOS의 ATS, 안드로이드의 cleartext 차단). 그래서 앱은 처음부터 HTTPS가 전제예요.
        </p>
        <Code>{CODE_TLS}</Code>
        <p>
          앱만의 한 겹이 <strong>인증서 고정(Certificate Pinning)</strong>이에요. 일반 HTTPS는
          "공인기관(CA)이 서명한 인증서면 믿는다"인데, 고정은 <strong>"우리 서버의 바로 그
          인증서만 믿는다"</strong>고 지문을 앱에 미리 새겨 둡니다. 그러면 가짜 CA를 동원한
          중간자(MITM) 공격까지 막을 수 있죠. 대신 <strong>서버 인증서를 갱신하면 앱도 같이
          업데이트</strong>해야 하는 부담이 있어, 신중히 도입하는 기법입니다.
        </p>
        <div className="tip">
          <b>웹에서 눈으로 확인</b> 우리 플랫폼을 열고 <span className="kbd">F12</span> →{' '}
          <span className="kbd">Network</span> 탭에서 요청 URL이 <span className="icode">https://</span>로
          시작하는지 보세요. 로그인은 비밀번호를 실어 보내니 <strong>반드시 HTTPS여야</strong>{' '}
          합니다. 앱도 정확히 같은 이유로 평문 통신을 금지해요.
        </div>
      </Section>

      <Section n={5} title="스토어 심사의 보안 기준" sub="웹 배포와 가장 다른 리듬 — 심사를 통과해야 나간다">
        <p>
          웹은 우리가 서버에 올리면 끝이지만, 앱은 <strong>애플 앱스토어·구글 플레이의 심사</strong>를
          통과해야 사용자에게 갑니다. 심사에서 보안·개인정보는 큰 비중을 차지해요. 핵심은
          "요청한 권한을 정말 그 용도로만 쓰는가", "어떤 데이터를 왜 모으는지 투명하게 밝혔는가"
          입니다.
        </p>
        <Code>{CODE_REVIEW}</Code>
        <p>
          특히 구글 플레이의 <strong>'데이터 보안'</strong> 섹션과 애플의{' '}
          <strong>'앱 개인정보 보호'</strong> 라벨은, 앱이 수집하는 데이터를 사용자가 설치 전에
          볼 수 있게 강제합니다. 개인정보처리방침 URL도 필수고요. 배경 위치·SMS·연락처처럼{' '}
          <strong>민감한 권한일수록 정당화가 까다롭습니다.</strong> 여기서도 결론은 섹션 2와
          같아요 — <strong>최소 권한</strong>이 심사 통과의 지름길입니다.
        </p>
        <div className="warn">
          <b>배포 리듬이 다르다</b> 웹은 고쳐서 푸시하면 바로 반영되지만, 앱은 거부되면 사유를
          받고 <strong>고쳐서 재심사</strong>(며칠 걸릴 수 있음)를 받아야 해요. 게다가 사용자가
          업데이트를 안 하면 <strong>취약한 옛 버전이 기기에 계속 남습니다.</strong> 그래서
          "처음부터 최소 권한·HTTPS·안전한 저장"으로 만드는 게 훨씬 이득이에요.
        </div>
      </Section>

      <Section n={6} title="흔한 앱 취약점" sub="입문자가 반복하는 실수 5가지 — 전부 앞 섹션의 응용">
        <p>
          지금까지 배운 걸 "이렇게 하면 뚫린다" 관점으로 뒤집어 보면 취약점 목록이 됩니다.
          입문자가 가장 자주 만드는 다섯 가지는 대부분 앞 섹션에서 이미 다룬 것들이에요.
          (업계에선 <span className="icode">OWASP Mobile Top 10</span>이라는 표준 목록으로
          정리해 두고 있어요.)
        </p>
        <Code>{CODE_VULN}</Code>
        <p>
          다섯 개를 관통하는 한 문장이 <strong>"클라이언트를 믿지 마라"</strong>입니다. 다섯 번째
          — <strong>클라이언트 과신</strong>이 특히 무서워요. "관리자 메뉴를 앱에서 숨겼으니
          안전하다"고 생각하지만, 앱은 뜯어볼 수 있으니 <strong>숨긴 화면은 언제든 드러납니다.</strong>{' '}
          진짜 권한 검사·금액 계산·본인 확인은 <strong>반드시 서버가 다시</strong> 해야 해요.
          화면을 감추는 건 편의(UX)일 뿐, 보안이 아닙니다.
        </p>
        <div className="tip">
          <b>우리 코드로 이미 경험한 것</b> 우리 <span className="icode">App.jsx</span>의{' '}
          <span className="icode">RequireMentor</span> 가드는 학생이 <span className="icode">/mentor</span>{' '}
          주소를 직접 쳐도 돌려보내지만, 그 파일 주석은 분명히 말해요 — "진짜 보안은
          서버(API)가 담당한다." 바로 이게 "클라이언트를 믿지 마라"의 실천이에요.
        </div>
      </Section>

      <Section n={7} title="우리 플랫폼 보안 원칙과의 공통점" sub="새로 배운 게 아니다 — 이미 하던 걸 앱으로 옮길 뿐">
        <p>
          여기까지 오면 반전이 하나 있어요. 앱 보안의 수칙 대부분을{' '}
          <strong>우리 플랫폼이 이미 지키고 있다</strong>는 겁니다. 트러스트 경계가 더
          바깥(공격자 기기)으로 밀려났을 뿐, 지켜야 할 원칙은 웹에서 배운 것과 똑같아요.
        </p>
        <Code>{CODE_OURS}</Code>
        <p>
          정리하면 — <strong>최소 권한</strong>(방화벽·라우팅 가드),{' '}
          <strong>HTTPS</strong>(네트워크 코스의 TLS), <strong>비밀은 평문 금지</strong>(BCrypt
          해싱), <strong>서버가 최종 심판</strong>(App.jsx 주석 그대로). 앱에서는 여기에{' '}
          <strong>토큰을 Keychain/Keystore에</strong>, <strong>필요하면 인증서 고정</strong>이
          더해질 뿐이에요. 즉 여러분은 이미 앱 보안의 감각을 웹 코드에서 익힌 셈입니다.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> 두 파일을 나란히 열어 보세요. ①{' '}
          <span className="icode">backend/.../config/SecurityConfig.java</span> — 비밀번호가 어떻게
          해싱되는지(BCrypt). ② <span className="icode">frontend/src/App.jsx</span> — 라우팅
          가드와 "진짜 보안은 서버가 담당한다" 주석. 이 두 개가 앱 보안 원칙의{' '}
          <strong>웹 버전 실물 교재</strong>예요.
        </div>
      </Section>

      <div className="step-card">
        <div className="step-body">
          <h3 style={{ marginBottom: 6 }}>🔐 여기까지 왔다면</h3>
          <p className="muted">
            이제 앱 보안이 웹과 <strong>왜</strong> 다른지 한 문장으로 말할 수 있어요 —
            "코드가 사용자 기기에 설치돼 남기 때문". 그 한 가지 차이에서 권한 모델·저장소
            보안·통신 보안·스토어 심사가 갈라져 나왔고, 그 뿌리는 결국{' '}
            <strong>우리 플랫폼이 이미 지키는 최소 권한·HTTPS·해싱·"서버가 최종 심판"과 같다</strong>는
            것도 확인했습니다. 안전하게 만든 앱은 이제 세상에 내보낼 차례예요 —{' '}
            <Link to="/learn/app-store-deploy"><strong>앱 스토어 배포</strong></Link> 코스에서
            심사를 통과해 실제 사용자에게 앱을 올리는 길을 따라가 봅시다.
          </p>
        </div>
      </div>
    </div>
  );
}
