/* ── BOTTOM NAV (Mobile-first, TASK 2) ── */ :root{ --nav-h: 56px; --bottom-nav-h: calc(56px + env(safe-area-inset-bottom)); } body { padding-bottom: var(--bottom-nav-h); } /* Top nav: hidden on mobile, shown on desktop */ .top-nav{ display:none; } @media(min-width:700px){ .top-nav{ display:flex;align-items:center;gap:0;padding:0; border-bottom:1px solid var(--border); position:sticky;top:0;background:var(--bg);z-index:100;overflow-x:auto; } body { padding-bottom: 0; } .bottom-nav { display:none !important; } } /* Bottom nav: always visible on mobile */ .bottom-nav{ position:fixed;bottom:0;left:0;right:0; background:var(--surface); border-top:1px solid var(--border); display:flex;align-items:stretch; height:var(--bottom-nav-h); padding-bottom:env(safe-area-inset-bottom); z-index:200; -webkit-backdrop-filter:blur(12px); backdrop-filter:blur(12px); } .bottom-nav-item{ flex:1;display:flex;flex-direction:column;align-items:center; justify-content:center;gap:2px; border:none;background:none;cursor:pointer; color:var(--muted);font-family:var(--mono);font-size:8.5px; letter-spacing:.5px;padding:6px 2px; transition:color .18s;position:relative; -webkit-tap-highlight-color:transparent; min-width:0; } .bottom-nav-item .bni-icon{font-size:18px;line-height:1;transition:transform .18s} .bottom-nav-item.active{color:var(--green)} .bottom-nav-item.active .bni-icon{transform:scale(1.15)} .bottom-nav-item .bni-badge{ position:absolute;top:4px;right:calc(50% - 14px); background:var(--green);color:#000;font-size:7px;font-weight:700; padding:1px 3px;border-radius:2px;display:none; } .bottom-nav-item .bni-badge.show{display:block} /* Active indicator bar on top of item */ .bottom-nav-item::before{ content:'';position:absolute;top:0;left:20%;right:20%; height:2px;background:var(--green);border-radius:0 0 2px 2px; transform:scaleX(0);transition:transform .18s; } .bottom-nav-item.active::before{transform:scaleX(1)} /* page needs top padding adjustment */ .page{min-height:calc(100vh - var(--bottom-nav-h));} @media(min-width:700px){ .page{min-height:calc(100vh - 41px);} } /* Swipe hint shimmer on first load */ @keyframes swipeHint{ 0%{transform:translateX(0);opacity:.7} 50%{transform:translateX(-6px);opacity:1} 100%{transform:translateX(0);opacity:.7} }
admin' -- または ' OR '1'='1
SELECT * FROM users WHERE
username = 'admin'
AND password = '*****'
// ❌ 脆弱なコード query = "SELECT * FROM users WHERE username = '" + input + "'" // ✅ 安全なコード (プリペアドステートメント) stmt = db.prepare("SELECT * FROM users WHERE username = ?") stmt.execute([input]) // inputはデータとして扱われる
<script>alert('XSS')</script> または <img src=x onerror="alert(1)">
// ❌ 脆弱: ユーザー入力をそのままHTMLに挿入 element.innerHTML = userInput // ✅ 安全: テキストとして扱う element.textContent = userInput // ✅ または DOMPurify でサニタイズ element.innerHTML = DOMPurify.sanitize(userInput)
<form action="vault.app/transfer"
method="POST">
<input name="amount" value="99999">
<!-- 自動送信スクリプト -->
</form>atob() または Buffer.from(str, 'base64').toString()