Build Chrome Extensions · Part 9 — Permissions & Security
The permission model: activeTab, optional permissions and runtime requests, host permissions, the content security policy, and how to write an extension that users install and reviewers trust. With an interactive permissions inspector.
Every permission you request is shown to the user at install time as a warning, and to Google when they review you {Mỗi quyền bạn xin được hiện cho user lúc cài như một cảnh báo, và cho Google khi họ duyệt bạn}. Over-asking is the number-one reason extensions lose installs and get rejected {Xin quá đà là lý do số một khiến extension mất lượt cài và bị từ chối}. The whole game is least privilege {Cả trò chơi là đặc quyền tối thiểu}.
Toggle permissions below and watch the consent warning and risk meter respond {Bật/tắt quyền bên dưới và xem cảnh báo đồng ý và đồng hồ rủi ro phản ứng}:
1. Two kinds of permission {Hai loại quyền}
- API permissions — access to
chrome.*APIs, listed inpermissions(e.g.storage,tabs,scripting,alarms) {Quyền API — truy cập APIchrome.*, liệt kê trongpermissions}. - Host permissions — access to specific sites’ data, listed in
host_permissions(e.g.https://*.example.com/*) {Host permissions — truy cập dữ liệu của site cụ thể, liệt kê tronghost_permissions}.
{
"permissions": ["storage", "scripting"],
"host_permissions": ["https://*.example.com/*"]
}
Host permissions are the scary ones — <all_urls> triggers “Read and change all your data on all websites”, which terrifies users {Host permissions là cái đáng sợ — <all_urls> kích “Đọc và thay đổi mọi dữ liệu của bạn trên mọi website”, làm user khiếp}. Watch the risk bar spike when you add it {Xem thanh rủi ro tăng vọt khi bạn thêm nó}.
2. activeTab — the permission that asks for nothing {activeTab — quyền không xin gì}
activeTab is the secret weapon for click-driven extensions {activeTab là vũ khí bí mật cho extension điều khiển bằng click}. It grants temporary access to the current tab — but only after the user invokes your extension (clicks the icon, uses a shortcut, or a context menu) — with no install warning at all {Nó cấp truy cập tạm thời tới tab hiện tại — nhưng chỉ sau khi user gọi extension (bấm icon, dùng phím tắt, hay context menu) — không cảnh báo cài đặt nào}.
{ "permissions": ["activeTab", "scripting"] }
chrome.action.onClicked.addListener(async (tab) => {
// activeTab now grants access to THIS tab, just-in-time
await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: () => document.body.style.filter = "grayscale(1)",
});
});
If your extension only acts when the user clicks, prefer activeTab over broad host permissions — same power, zero scary warning {Nếu extension chỉ hành động khi user bấm, ưu tiên activeTab hơn host permissions rộng — cùng sức mạnh, không cảnh báo đáng sợ}.
3. Optional permissions — ask at runtime {Quyền tùy chọn — xin lúc chạy}
Don’t request a powerful permission upfront if only some users need it {Đừng xin quyền mạnh ngay từ đầu nếu chỉ vài user cần}. Declare it as optional and request it on demand, in response to a user gesture {Khai báo nó là tùy chọn và xin theo yêu cầu, đáp lại một thao tác của user}:
{
"optional_permissions": ["downloads"],
"optional_host_permissions": ["https://*/*"]
}
// inside a click handler — must be user-initiated
const granted = await chrome.permissions.request({
permissions: ["downloads"],
origins: ["https://example.com/*"],
});
if (granted) startDownload();
This keeps your install-time warnings minimal and gives users control {Điều này giữ cảnh báo lúc cài tối thiểu và cho user quyền kiểm soát}. You can chrome.permissions.remove(...) later, and check with chrome.permissions.contains(...) {Bạn có thể chrome.permissions.remove(...) sau, và kiểm tra với chrome.permissions.contains(...)}.
4. The content security policy {Chính sách bảo mật nội dung}
MV3 enforces a strict CSP on your extension pages {MV3 áp CSP nghiêm ngặt lên các trang extension của bạn}. The rules you must internalize {Quy tắc phải thấm}:
- No remote code. You cannot load
<script src="https://cdn...">— all JS must ship inside the extension {Không code từ xa. Bạn không thể tải<script src="https://cdn...">— mọi JS phải đóng gói trong extension}. - No inline scripts. No
<script>code</script>and noonclick="..."attributes — use external files andaddEventListener{Không script inline. Không<script>code</script>và không thuộc tínhonclick="..."— dùng file ngoài vàaddEventListener}. - No
eval/new Function. Dynamic code execution is blocked {Khôngeval/new Function. Thực thi code động bị chặn}.
This is exactly why bundlers matter (Part 11) — you ship a self-contained bundle, never a CDN link {Đây chính là vì sao bundler quan trọng (Phần 11) — bạn ship một bundle tự chứa, không bao giờ link CDN}.
5. Other security responsibilities {Trách nhiệm bảo mật khác}
- Validate every message, especially from content scripts and
onMessageExternal— treat them as untrusted input {Xác thực mọi tin nhắn, nhất là từ content script vàonMessageExternal— coi chúng là input không tin cậy}. - Never inject untrusted strings as HTML —
innerHTMLwith page data is an XSS hole; usetextContentor sanitize {Không bao giờ tiêm chuỗi không tin cậy làm HTML —innerHTMLvới dữ liệu trang là lỗ XSS; dùngtextContenthoặc sanitize}. - Scope
web_accessible_resourcesto specific files and origins, not<all_urls>{Khoanhweb_accessible_resourcesvào file và origin cụ thể, không<all_urls>}. - Don’t leak secrets. Anything shipped in the extension is readable by anyone who unzips it — no embedded API secrets {Không rò bí mật. Mọi thứ ship trong extension đều đọc được bởi ai giải nén — không nhúng API secret}.
6. Writing for reviewers {Viết cho reviewer}
The Chrome Web Store review checks that every permission is justified by visible functionality {Duyệt Chrome Web Store kiểm tra mọi quyền có lý do bởi chức năng nhìn thấy được}. Practical rules {Quy tắc thực dụng}:
- Request the narrowest host pattern that works {Xin mẫu host hẹp nhất mà vẫn chạy}.
- Prefer
activeTaband optional permissions {Ưu tiênactiveTabvà quyền tùy chọn}. - Remove permissions you stopped using {Bỏ quyền bạn đã ngừng dùng}.
- Have a clear privacy policy if you touch user data {Có chính sách bảo mật rõ nếu chạm dữ liệu user}.
A lean permission set earns trust, installs, and a fast review {Bộ quyền gọn gàng kiếm được niềm tin, lượt cài, và duyệt nhanh}.
7. Exercises {Bài tập}
1. Your extension grays out the page when the user clicks the icon. You requested host_permissions: ["<all_urls>"]. Is there a less alarming option? {Extension làm xám trang khi user bấm icon. Bạn xin host_permissions: ["<all_urls>"]. Có lựa chọn ít đáng sợ hơn không?}
Solution {Lời giải}
Use activeTab + scripting — you act only on click, so you get current-tab access with no install warning {Dùng activeTab + scripting — bạn chỉ hành động khi bấm, nên có truy cập tab hiện tại mà không cảnh báo cài đặt}.
2. You try to load a charting library from a CDN with <script src="https://cdn.../chart.js"> and nothing runs. Why? {Bạn thử tải thư viện biểu đồ từ CDN bằng <script src="https://cdn.../chart.js"> và không gì chạy. Vì sao?}
Solution {Lời giải}
MV3’s CSP forbids remote code. Bundle the library into your extension and reference the local file {CSP của MV3 cấm code từ xa. Đóng gói thư viện vào extension và tham chiếu file cục bộ}.
3. Only 5% of users use your “export to Google Drive” feature, which needs a broad permission. How do you avoid scaring the other 95%? {Chỉ 5% user dùng tính năng “xuất sang Google Drive”, cần một quyền rộng. Làm sao tránh dọa 95% còn lại?}
Solution {Lời giải}
Declare it as an optional permission and request it at runtime, inside the feature’s click handler, only for the users who use it {Khai báo nó là quyền tùy chọn và xin lúc chạy, trong handler click của tính năng, chỉ cho user dùng nó}.
Stretch {Nâng cao}: in the inspector, toggle <all_urls> and cookies together and watch the risk bar go red — then replace them with activeTab and see it drop to green {trong inspector, bật <all_urls> và cookies cùng lúc và xem thanh rủi ro đỏ — rồi thay bằng activeTab và xem nó xuống xanh}.
Key takeaways {Điểm chính}
- Practice least privilege — every permission is a warning and a review risk {Thực hành đặc quyền tối thiểu — mỗi quyền là một cảnh báo và rủi ro duyệt}.
activeTabgrants current-tab access on user action with no warning {activeTabcấp truy cập tab hiện tại khi user hành động mà không cảnh báo}.- Use optional permissions for features only some users need {Dùng quyền tùy chọn cho tính năng chỉ vài user cần}.
- MV3’s CSP forbids remote and inline code — bundle everything {CSP của MV3 cấm code từ xa và inline — đóng gói mọi thứ}.
- Validate untrusted input and never
innerHTMLpage data {Xác thực input không tin cậy và không bao giờinnerHTMLdữ liệu trang}.
Next up {Tiếp theo}
Part 10 — The powerful APIs: tabs, scripting, contextMenus, commands (keyboard shortcuts), and notifications — the toolkit that turns a toy into a real product {Phần 10 — Các API mạnh mẽ: tabs, scripting, contextMenus, commands (phím tắt), và notifications — bộ công cụ biến đồ chơi thành sản phẩm thật}.