Lập trình · 02/10/2026

Permissions Policy thực chiến: Giới hạn camera, microphone và iframe

Một trang web không nên mặc định trao camera, microphone, vị trí hay fullscreen cho mọi đoạn mã và iframe mà nó nhúng. Header Permissions-Policy cho phép website đặt ranh giới capability ngay tại trình duyệt: feature nào bị tắt hoàn toàn, feature nào chỉ dành cho chính origin, và frame bên thứ ba nào được quyền sử dụng.

Permissions Policy thực chiến: Giới hạn camera, microphone và iframe

Một trang web không nên mặc định trao camera, microphone, vị trí hay fullscreen cho mọi đoạn mã và iframe mà nó nhúng. Header Permissions-Policy cho phép website đặt ranh giới capability ngay tại trình duyệt: feature nào bị tắt hoàn toàn, feature nào chỉ dành cho chính origin, và frame bên thứ ba nào được quyền sử dụng.

Policy này không tự cấp quyền cho website. Người dùng vẫn có quyền từ chối camera, microphone hoặc vị trí; HTTPS, permission prompt và các điều kiện của từng API vẫn còn nguyên. Permissions Policy chỉ đặt thêm một trần quyền: nếu policy cấm, code không thể vượt qua bằng cách xin người dùng.

1. Permissions Policy giải quyết vấn đề gì?

Đặc tả Permissions Policy của W3C định nghĩa cơ chế bật hoặc tắt có chọn lọc các browser feature/API cho document và nội dung nhúng. Cơ chế này trước đây có tên Feature Policy; cú pháp header hiện đại đã thay đổi.

Giả sử trang sản phẩm nhúng video, bản đồ, chat hỗ trợ và analytics. Nếu không có policy rõ ràng, việc một dependency thay đổi hoặc một iframe được thêm nhầm có thể mở rộng capability ngoài chủ đích. Permissions Policy biến kỳ vọng “analytics không cần microphone” thành quy tắc được trình duyệt enforce.

Policy là giới hạn tối đa, không phải nút “Allow” thay người dùng. Một feature chỉ hoạt động khi policy cho phép, browser hỗ trợ, trang đáp ứng điều kiện bảo mật và người dùng cấp quyền nếu API yêu cầu.

2. Ba allowlist quan trọng: rỗng, self và origin cụ thể

Permissions-Policy: camera=(), microphone=(), geolocation=(self), fullscreen=(self "https://video.example")
Cú phápÝ nghĩaDùng khi
feature=()Tắt feature cho document và các frame conỨng dụng không có nhu cầu hợp lệ
feature=(self)Cho phép origin của documentChỉ code first-party cần feature
feature=(self "https://a.example")Header cho phép thêm origin chính xácMột nhà cung cấp nhúng đã được duyệt
feature=*Cho phép mọi origin theo semantics của featureHiếm khi phù hợp với capability nhạy cảm

Origin gồm scheme, host và port. https://video.example không tự bao gồm mọi subdomain hay một port khác. Đây là đặc tính có ích: hãy liệt kê nhỏ nhất có thể thay vì dùng wildcard để “sửa nhanh” một iframe bị lỗi.

3. Header và iframe allow là hai lớp giao nhau

Response header đặt policy cho top-level document và giới hạn tối đa có thể truyền xuống. Thuộc tính allow trên từng <iframe> đặt container policy cho frame cụ thể:

Permissions-Policy: camera=(self "https://meet.example"), microphone=(self "https://meet.example"), geolocation=()
<iframe
  src="https://meet.example/room/123"
  allow="camera https://meet.example; microphone https://meet.example; fullscreen"
  sandbox="allow-scripts allow-same-origin allow-forms"
  title="Cuộc họp trực tuyến">
</iframe>

Origin xuất hiện trong header chưa đủ để frame cross-origin sử dụng feature; frame còn phải được delegate qua allow. Ngược lại, allow không thể nới rộng một feature đã bị header cha chặn. Document bên trong cũng có thể tự gửi policy chặt hơn.

Thuộc tính allow="camera; microphone" thường dùng allowlist mặc định gắn với origin trong src. Viết origin tường minh giúp việc review rõ hơn, nhất là khi frame có thể navigate. Nếu src chuyển sang origin không nằm trong policy, capability không nên âm thầm đi theo.

4. Bắt đầu bằng inventory, không bằng danh sách header trên mạng

Mỗi policy-controlled feature có default allowlist và mức hỗ trợ trình duyệt riêng. Tên feature cũng phát triển theo tiêu chuẩn. Vì vậy không nên chép một header dài từ blog rồi cho rằng mọi directive đều được enforce giống nhau.

  1. Liệt kê first-party code, iframe và third-party script đang dùng capability nào.
  2. Ghi owner và luồng người dùng chứng minh nhu cầu.
  3. Tắt trước các feature nhạy cảm chắc chắn không dùng.
  4. Giới hạn feature còn lại về self.
  5. Delegate từng origin/frame bên thứ ba sau khi kiểm thử.

Một baseline thận trọng cho website nội dung không có gọi video hoặc bản đồ có thể là:

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), serial=()

Đây chỉ là ví dụ. Trước khi dùng, kiểm tra feature identifier và browser support hiện tại cho tập trình duyệt của sản phẩm. Directive không được user agent nhận diện có thể bị bỏ qua; header tồn tại không chứng minh mọi capability đã bị khóa.

5. Đừng nhầm Permissions Policy với permission prompt

Ba quyết định xảy ra ở các lớp khác nhau:

LớpCâu hỏiVí dụ
Permissions PolicyDocument/frame này có được phép dùng feature?Chỉ frame họp được dùng camera
Permission của người dùngNgười dùng có đồng ý cho origin truy cập?Allow camera lần này
Logic ứng dụngUser/account có được thực hiện hành động?Chỉ thành viên phòng họp được tham gia

Policy không thay authentication hoặc authorization. Việc một frame được phép gọi API camera không có nghĩa người dùng đã cấp camera, càng không chứng minh tài khoản được quyền vào cuộc họp.

6. Cấu hình trong Nginx và ứng dụng PHP

Nginx có thể thêm header trên các response HTML thuộc ứng dụng:

add_header Permissions-Policy \
  'camera=(), microphone=(), geolocation=(self), fullscreen=(self "https://video.example")' \
  always;

PHP có thể tạo một header cố định:

$directives = [
    'camera=()',
    'microphone=()',
    'geolocation=(self)',
    'fullscreen=(self "https://video.example")',
];

header('Permissions-Policy: '.implode(', ', $directives));

Ưu tiên một nguồn cấu hình duy nhất. Nếu CDN, Nginx và ứng dụng cùng thêm header, kết quả có thể khó quan sát và khó rollback. Kiểm tra response cuối cùng từ bên ngoài hạ tầng, không chỉ unit test của ứng dụng.

7. Permissions Policy không thay iframe sandbox và CSP

  • iframe sandbox hạn chế script, form, navigation, popup và nhiều hành vi của frame.
  • Content Security Policy kiểm soát nguồn tài nguyên, script và các sink liên quan.
  • Permissions Policy kiểm soát feature/capability mà document hoặc frame có thể sử dụng.

Ba cơ chế giải quyết ba trục khác nhau và thường nên dùng cùng nhau. Một iframe được phép camera vẫn cần sandbox phù hợp nếu nội dung không hoàn toàn tin cậy. Một CSP mạnh cũng không tự cấm geolocation. Ngược lại, tắt microphone không ngăn frame chạy script độc hại.

8. Thiết kế policy theo capability, không theo nhà cung cấp

Tránh cấu hình kiểu “cho iframe A mọi thứ vì A là đối tác”. Hãy hỏi từng capability:

  • Video player cần fullscreen nhưng có thật sự cần camera và microphone không?
  • Bản đồ cần geolocation hay chỉ nhận tọa độ do ứng dụng truyền?
  • Widget thanh toán cần payment capability hay chỉ redirect tới trang riêng?
  • Chat hỗ trợ có cần clipboard, display capture hoặc autoplay không?

Capability review nhỏ hơn vendor review. Khi thay nhà cung cấp, đội ngũ biết chính xác contract nào phải chuyển; khi vendor bổ sung SDK mới, browser không tự cấp feature ngoài policy.

9. Rollout mà không làm hỏng production

Bản đặc tả mới định nghĩa Permissions-Policy-Report-Only và reporting, nhưng mức hỗ trợ có thể khác giữa trình duyệt. Đừng dựa duy nhất vào report-only nếu chưa xác minh trên browser matrix của mình. Một kế hoạch thực dụng:

  1. Thu thập inventory từ source, tag manager, danh sách iframe và hành vi thực tế.
  2. Bật policy nhỏ trên staging; test luồng camera, microphone, vị trí, payment và fullscreen.
  3. Canary một nhóm route hoặc tỷ lệ traffic; theo dõi lỗi JavaScript và conversion.
  4. Enforce các directive chắc chắn như capability không dùng trước.
  5. Thêm directive theo từng đợt, ghi owner và ngày review cho mỗi ngoại lệ.

Thông báo vi phạm trên console thường chỉ là điểm bắt đầu. Cần test kết quả người dùng: permission prompt có xuất hiện đúng lúc, video call có media, bản đồ có fallback, iframe fullscreen hoạt động và luồng thanh toán không bị kẹt.

10. Các lỗi cấu hình thường gặp

  • Dùng cú pháp Feature Policy cũ như camera 'none' trong header mới thay vì camera=().
  • Cho origin trong header nhưng quên allow trên iframe cross-origin.
  • Thêm allow và kỳ vọng nó vượt qua policy chặt hơn từ document cha.
  • Dùng wildcard cho camera/microphone chỉ để sửa nhanh một integration.
  • Coi subdomain là origin giống nhau; self không có nghĩa “mọi subdomain”.
  • Không kiểm tra redirect hoặc navigation của iframe sang origin khác.
  • Giả định directive không báo lỗi đồng nghĩa đã được browser hỗ trợ và enforce.

11. Checklist trước khi phát hành

  • Header production có cú pháp hiện đại và chỉ xuất hiện theo cấu hình dự kiến.
  • Danh sách feature dựa trên nhu cầu thật và browser support được kiểm chứng.
  • Capability nhạy cảm không dùng đã đặt allowlist rỗng.
  • Origin third-party được liệt kê chính xác, không dùng wildcard không cần thiết.
  • Mỗi iframe có allow, sandbox và title phù hợp.
  • Đã test cả trang top-level, iframe same-origin, cross-origin và sau redirect.
  • Permission bị từ chối có UI fallback; không bỏ qua kiểm tra bảo mật hoặc nghiệp vụ.
  • Có canary, metric lỗi, rollback và lịch rà soát exception.

Permissions Policy tốt không cố liệt kê mọi API của trình duyệt; nó thể hiện contract capability nhỏ nhất mà sản phẩm thật sự cần. Dùng header để đặt trần toàn trang, dùng iframe allow để delegate chính xác, rồi kết hợp sandbox, CSP và permission của người dùng để tạo nhiều lớp kiểm soát độc lập.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.