[Bảo mật] Cách phòng chống XSS và CSRF lập trình web
[Bảo mật] Cách phòng chống XSS và CSRF lập trình web
1. XSS là gì?
XSS xảy ra khi script độc hại được inject và chạy trong browser của user do frontend render nội dung không an toàn.
Cách phòng chống XSS (từ quan trọng → ít quan trọng)
1) Không render HTML trực tiếp từ user input
-
Tránh dùng:
-
dangerouslySetInnerHTML(React) -
v-html(Vue)
-
-
Nếu bắt buộc dùng → phải sanitize
👉 Đây là nguyên nhân XSS phổ biến nhất.
2) Escape / Encode dữ liệu khi render
-
Render text thay vì HTML
-
Framework như React/Vue tự động escape khi render string
Ví dụ an toàn:
3) Sanitize HTML khi thật sự cần
-
Dùng library như:
-
DOMPurify
-
-
Chỉ cho phép whitelist tag/attribute cần thiết
👉 Không tự viết sanitizer.
4) Không tin data từ API
-
Data từ backend hoặc third-party cũng có thể gây XSS
-
Coi tất cả data là “untrusted”
5) Không lưu script trong localStorage / cookie
-
Tránh lưu HTML / JS động
-
Cẩn thận với token nếu bị XSS → có thể bị đánh cắp
6) Dùng Content Security Policy (CSP)
-
CSP giúp:
-
Chặn inline script
-
Chặn load script từ domain lạ
-
-
Đây là lớp bảo vệ bổ sung rất mạnh
7) Cẩn thận với third-party script
-
Analytics, ads, widget…
-
Chỉ dùng nguồn đáng tin
-
Tránh copy script từ web không rõ nguồn
Frontend cần nhớ
-
XSS là lỗi rất nguy hiểm, có thể đánh cắp token và session
-
Frontend đóng vai trò lớn nhất trong việc phòng tránh XSS
Câu chốt khi phỏng vấn
Nguyên tắc của mình là: không render HTML không tin cậy; nếu bắt buộc thì phải sanitize và kết hợp CSP.
2. CSRF là gì?
CSRF xảy ra khi browser tự động gửi cookie kèm request, khiến user vô tình thực hiện action khi đang đăng nhập.
View: https://viblo.asia/p/ky-thuat-tan-cong-csrf-va-cach-phong-chong-amoG84bOGz8P
Cách phòng chống tấn công CSRF
1) CSRF Token (cách phổ biến nhất)
-
Server sinh ra CSRF token
-
Frontend gửi token này kèm theo request (header hoặc body)
-
Server kiểm tra token trước khi xử lý
👉 Chỉ request hợp lệ mới được chấp nhận.
2) SameSite Cookie
-
Set cookie với:
-
SameSite=LaxhoặcSameSite=Strict
-
-
Giảm khả năng cookie bị gửi kèm request từ site khác
👉 Đây là cách đơn giản và rất hiệu quả.
3) Check Origin / Referer
-
Backend kiểm tra header
OriginhoặcReferer -
Nếu không đúng domain → reject request
Frontend cần:
-
Gửi request đúng origin
-
Không bypass cơ chế này
4) Không dùng GET cho action thay đổi dữ liệu
-
Tránh dùng GET cho:
-
create / update / delete
-
-
Dùng POST / PUT / DELETE đúng chuẩn
👉 Giảm nguy cơ bị trigger ngầm.
5) Không dùng cookie cho API công khai nếu không cần
-
Nếu dùng token-based auth (Authorization header):
-
CSRF gần như không còn là vấn đề
-
-
Nhưng phải cẩn thận với XSS
Frontend cần nhớ gì?
-
CSRF không xử lý một mình ở frontend
-
Frontend cần:
-
Gửi CSRF token đúng cách
-
Phối hợp backend set cookie và header đúng
-
Câu chốt khi phỏng vấn
CSRF chủ yếu xảy ra khi dùng cookie-based authentication; cách hiệu quả nhất là kết hợp CSRF token và SameSite cookie.
1) Kinh nghiệm tích hợp frontend với CI/CD (GitHub Actions, CircleCI…)
Mình thường set CI/CD cho frontend theo các bước “chuẩn” sau:
-
CI khi mở PR / push
-
Cài deps + cache (npm/yarn/pnpm)
-
lint+typecheck(TS) -
test(unit/integration) -
buildđể bắt lỗi build sớm -
(tuỳ dự án) chạy E2E (Playwright/Cypress) cho flow chính
-
-
CD khi merge vào main/release
-
Build artifact (Next/Nuxt / SPA)
-
Upload lên hosting (S3+CloudFront, Vercel, Netlify, ECS…)
-
Inject env đúng môi trường (staging/prod)
-
Auto tag/version + generate changelog (nếu team dùng)
-
Notify Slack khi deploy xong / fail
-
Những điểm mình hay chú ý để pipeline “mượt”:
-
Cache dependency để giảm thời gian chạy
-
Tách job theo mức độ quan trọng (PR nhẹ, main nặng hơn)
-
Chặn merge nếu fail (required checks)
-
Có staging trước production, và có rollback (giữ artifact/build cũ)
2) Khi xảy ra bug production, anh/chị debug qua log như thế nào?
Mình thường debug theo quy trình khá thực dụng:
-
Xác định phạm vi lỗi
-
Lỗi xảy ra với user nào, feature nào, browser nào, thời điểm nào
-
Có phải sau deploy mới bị không (so changelog / commit)
-
Dựa vào error tracking & log
-
Ưu tiên xem stack trace (Sentry/Datadog/CloudWatch…)
-
Tìm theo:
-
error message
-
URL/route
-
release version
-
frequency (bao nhiêu user bị)
-
-
Correlate bằng request id / trace id
-
Nếu hệ thống có
requestId/traceId:-
Lấy id từ frontend log/error
-
Tra qua backend log để nối “end-to-end”
-
-
Nhờ vậy biết lỗi ở FE, BE hay do network/timeout
-
Reproduce nhanh
-
Dùng thông tin từ log: payload, role, browser, step
-
Nếu không reproduce được: thêm log/metric (tối thiểu, không leak data)
-
Fix theo mức độ khẩn
-
Nếu ảnh hưởng lớn: ưu tiên hotfix / rollback
-
Nếu không quá lớn: fix + thêm test để tránh tái diễn
Các lưu ý mình luôn nhắc:
-
Không log dữ liệu nhạy cảm (token, password, PII)
-
Log nên có context: route, user role (ẩn danh), version, feature flag, timing
1) Can you explain a technical decision in English?
Sample answer (simple, clear English):
In one project, we chose to use TypeScript with strict mode instead of plain JavaScript.
The reason was to reduce runtime bugs and make refactoring safer as the application grew.
We focused on typing API boundaries and shared components, not every single variable, to avoid over-engineering.
As a result, onboarding new members became easier and we caught many issues earlier during development.
👉 Điểm cộng:
-
Không dùng từ vựng quá phức tạp
-
Giải thích why → how → result
2) What makes you resonate with Andpad’s mission and values?
Sample answer (phù hợp công ty product / Nhật):
What resonates with me about Andpad is its focus on solving real problems in the construction industry, not just building technology for technology’s sake.
Digital transformation in this field can significantly improve efficiency, reduce manual work, and support people on the ground.
I also value Andpad’s emphasis on long-term product quality, teamwork, and continuous improvement, which aligns well with how I like to work as an engineer.
👉 Điểm cộng:
-
Nhắc đến DX, real business impact
-
Phù hợp mindset product company Nhật