結論(Permissions-Policy)
Permissions-Policyとは、カメラ、マイク、位置情報、決済、USBなどの強力なブラウザ機能を、そのページと埋め込まれたiframeがどの範囲で使えるかを宣言するレスポンスヘッダー(旧称Feature-Policy)です。使わない機能を camera=() のように空の許可リストで無効化すると、スクリプトが注入されたり外部ウィジェットが不正な動作をしたりしても、それらの機能を呼び出せなくなります。書式を1か所でも誤るとヘッダー全体が無視される点に注意が必要です。
この記事のポイント
- 書き方は「機能名=許可リスト」。()で無効化、(self)で同一オリジンのみ、*で全オリジンに許可します。
- Structured Fieldsの辞書として解析できないと、ヘッダー全体が無視されます(旧Feature-Policy書式・=前後の空白・大文字キー・末尾カンマに注意)。
- 自治体サイトでは camera=(), microphone=(), geolocation=(self), payment=() などから始めるのが現実的です。
- MDNはBaselineではないと注意しており、多層防御の1つとして位置づけます。
- セキュリティAIチェッカーは正しい書式で強い権限を全許可していなければ○、未設定・構文不正・camera=*等は△(重み1)です。
| 診断項目名 | Permissions-Policy |
|---|---|
| 項目ID | headers.permissions |
| 分類 | セキュリティヘッダー |
| 重大度・配点の重み | 低(low) 重み 1 |
| 関連する標準・ガイドライン | W3C Permissions Policy(Editor's Draft。旧称 Feature Policy)、RFC 9651 / RFC 8941(Structured Field Values for HTTP。ヘッダーの構文)、OWASP WSTG-CONF-14(Other HTTP Security Header Misconfigurations)、OWASP Secure Headers Project(推奨値の例を掲載)、CWE-693(Protection Mechanism Failure。OWASP ZAP アラート 10063 の分類)。OWASP ASVS 5.0.0 には Permissions-Policy を直接要求する要件はありません。 |
Permissions-Policy(パーミッションポリシー)とは
Permissions-Policyとは、カメラ、マイク、位置情報、決済、USB などの強力なブラウザ機能を、そのページと埋め込まれた iframe がどの範囲で使えるかを宣言するレスポンスヘッダーです。W3C の仕様で定義されており、旧称は Feature Policy です。
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=()
使わない機能を ()(空の許可リスト)で無効化しておくと、万一サイトにスクリプトが注入されたり、広告・外部ウィジェットが不正な動作をしたりしても、これらの機能を呼び出せなくなります。
自治体の公式サイトは、多くの場合カメラやマイクを使いません。一方で、地図での現在地表示、動画埋め込み、外部の予約・申請フォームなど、一部の機能を使う場面もあります。Permissions-Policy は、必要な機能だけを必要な配信元に許可する「最小権限」の宣言として位置づけられます。
Permissions-Policyの書き方(構文と許可リスト)
基本の構文
ヘッダーは Structured Fields(RFC 9651 / RFC 8941)の「辞書(Dictionary)」として解釈されます。各メンバーは 機能名=許可リスト の形で、カンマで区切って並べます。
| 許可リスト | 意味 |
|---|---|
* | すべてのオリジンに許可(別オリジンの iframe が実際に使うには、iframe の allow 属性による委譲も必要) |
() | 無効化(トップレベルでも iframe でも使えない) |
(self) | 同一オリジンのみ許可 |
(self "https://map.example.jp") | 同一オリジンと指定オリジンに許可 |
MDN によれば、* と () は単独で使う値で、self は他のオリジンと組み合わせられます。HTTP ヘッダーではオリジンを二重引用符で囲みます。iframe 側の allow 属性(allow="geolocation 'self'")は書式が異なります。
構文誤りに弱い(1か所の誤りで全体が無視される)
仕様では、ヘッダーが Structured Fields の辞書として解析できない場合、ポリシーは空として扱われます。つまり1か所の書式誤りでヘッダー全体が無視されます。よくある誤りは次のとおりです。
| よくある誤り | 誤った例 | 正しい例 |
|---|---|---|
| 旧 Feature-Policy の書式をそのまま書く | camera 'none'; microphone 'none' | camera=(), microphone=() |
= の前後に空白を入れる(辞書のキーと値の間に空白は許されない) | camera = () | camera=() |
| 大文字のキーを使う(キーは小文字) | Camera=() | camera=() |
| 末尾にカンマを付ける | camera=(), | camera=() |
ブラウザ対応
MDN は Permissions-Policy ヘッダーを「Baseline ではなく、広く使われている一部のブラウザでは動作しない」と注意しています。Chromium 系では広く実装されていますが、すべてのブラウザで同じ効果を期待することはできません。多層防御の1つとして位置づけ、これだけに頼らないことが大切です。
Permissions-Policyについてよくある誤解
- 「付けないとカメラが勝手に使われる」:カメラやマイク、位置情報の利用には、別途ユーザーの許可ダイアログが必要です。Permissions-Policy は、許可を求めること自体をできなくする追加の制限です。
- 「全機能を列挙しないと意味がない」:主要な強力機能(camera、microphone、geolocation、payment、usb など)から始めれば十分効果があります。ブラウザが知らない機能名は無視されるため、警告がコンソールに出ることはありますが動作は壊れません。
- 「
interest-cohort=()が必須」:FLoC 向けの指定で、現在は意味を持ちません。残っていても害はありません。
Permissions-Policyの診断基準(セキュリティAIチェッカー)
取得方法
- 入力URLへ GET を1回送り、リダイレクト(最大4回)後の最終応答の
Permissions-Policyヘッダーを評価します。追加の通信はしません。 - 旧
Feature-Policyヘッダーと iframe のallow属性は評価対象外です。
判定条件
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | ヘッダーがあり、カンマで区切った各メンバーが 小文字の機能名=値 の形で、camera / microphone / geolocation / payment のいずれも =* で全オリジンに許可していない | 重み1を満点加算 |
| △ 要確認(warn) | ヘッダーがない | 1×0.45=0.45点 |
| △ 要確認(warn) | 構文として解釈できないメンバーがある(Feature-Policy 書式、= 前後の空白、大文字キー、空メンバーなど)。ヘッダー全体が無視される可能性があるため | 1×0.45=0.45点 |
| △ 要確認(warn) | camera=*、microphone=*、geolocation=*、payment=* のいずれかがある(強い権限を全オリジンへ許可) | 1×0.45=0.45点 |
| × 要改善(fail)/対象外(na) | この項目では使いません | ― |
- 構文の確認は簡易的なもので、「各メンバーが小文字のキーで始まり、空白なしの
=の直後に値がある」ことを見ています。Structured Fields の完全な検証ではありません。 - 根拠欄には、ヘッダー値の先頭180文字、または検出した問題を表示します。
- 重大度を low、重みを1としているのは、ブラウザ対応が限定的で、未設定でもユーザー許可という別の防御があるためです。
自治体サイトでの判定例
| 応答ヘッダー | 判定 |
|---|---|
camera=(), microphone=(), geolocation=(self), payment=() | ○ |
geolocation=(self "https://map.example.jp"), camera=() | ○ |
camera 'none'; microphone 'none'(Feature-Policy 書式) | △(構文不正) |
camera = (), microphone = ()(空白入り) | △(構文不正) |
geolocation=* | △(全オリジンに許可) |
| ヘッダーなし | △ |
Permissions-Policyがないとどんなリスクがあるか
攻撃シナリオ
- 注入スクリプトによる機能悪用:XSS や改ざんでスクリプトが注入された場合、位置情報やカメラの許可を求めるダイアログを、公式サイトの名前で表示させることができます。住民は公式サイトだと信じて許可してしまうおそれがあります。Permissions-Policy で無効化していれば、ダイアログ自体を出せません。
- 埋め込みコンテンツからの権限要求:広告、SNS ウィジェット、外部フォームなどの iframe が乗っ取られたり、想定外の動作をしたりした場合に、強力な機能を要求する。許可リストを
selfや特定オリジンに限定すると、こうした要求を遮断できます。 - 全オリジン許可の誤設定:
geolocation=*のように書くと、どのオリジンの iframe に対してもallow属性で位置情報の利用を委譲できる状態になり、意図より広い権限を与えます。
想定される被害
- 住民の位置情報、カメラ映像、マイク音声の不正取得(ユーザーが許可した場合)
- 公式サイトを装った不審な権限要求による信用低下
いずれも他の不備(スクリプト注入、外部コンテンツの侵害)と組み合わさって初めて起きる被害であり、Permissions-Policy は被害を限定する多層防御です。スクリプト注入そのものへの対策は「Content Security Policy」、外部 iframe の権限制限は「外部iframeのsandbox」の項目で確認します。
Permissions-Policyの設定方法(Apache・nginx・IIS・Next.js)
推奨値の例
自治体公式サイトで、位置情報を自サイトの地図だけで使う場合の例です。実際に使っている機能を棚卸ししてから決めてください。
Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=(), usb=(), serial=(), hid=(), bluetooth=(), midi=(), display-capture=()
OWASP Secure Headers Project は、さらに多くの機能を () にした例を掲載しています。ただし fullscreen=() や autoplay=() を指定すると、埋め込み動画の全画面表示や自動再生ができなくなるため、動画を埋め込むサイトでは外してください。
Apache(.htaccess)
<IfModule mod_headers.c>
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(self), payment=(), usb=()"
</IfModule>
nginx
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(self), payment=(), usb=()" always;
IIS(web.config)
<httpProtocol>
<customHeaders>
<add name="Permissions-Policy" value="camera=(), microphone=(), geolocation=(self), payment=(), usb=()" />
</customHeaders>
</httpProtocol>
Next.js(Vercel)
// next.config.js
module.exports = {
async headers() {
return [{
source: "/:path*",
headers: [{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=(self), payment=(), usb=()",
}],
}];
},
};
外部埋め込みで機能を使う場合
外部の地図や予約システムを iframe で埋め込み、そこで位置情報を使う必要がある場合は、ヘッダーで該当オリジンを許可し、iframe 側でも allow 属性で委譲します。
Permissions-Policy: geolocation=(self "https://map.example.jp")
<iframe src="https://map.example.jp/embed" allow="geolocation"></iframe>
段階的導入とサイトを壊さないための注意点
- まず使っていない機能(camera、microphone、payment、usb など)だけを
()にします。 - 位置情報・全画面表示・自動再生・クリップボードなど、実際に使っている可能性がある機能は、ページを確認してから追加します。
- 設定後は Chrome の開発者ツールのコンソールに、Permissions-Policy の解析エラーや未知の機能名に関するメッセージが出ていないか確認します。構文エラーがあるとヘッダー全体が無視されます。
- 地図の「現在地」ボタン、動画の全画面表示、外部フォームの動作を実機で確認します。
設定後の確認方法
curl -sI https://www.example.lg.jp/ | grep -i permissions-policy
Chromium 系ブラウザでは、開発者ツールの Application パネルにある Frames の項目から、ページに適用された Permissions Policy を確認できます。設定後はセキュリティAIチェッカーで再診断し、根拠欄に構文不正や全オリジン許可の指摘が出ていないことを確認します。
よくある質問(FAQ)
Permissions-Policyの正しい書き方を教えてください。
「機能名=許可リスト」をカンマで区切って並べます。例は camera=(), microphone=(), geolocation=(self), payment=() です。キーは小文字で、= の前後に空白を入れず、オリジンを指定するときは (self "https://map.example.jp") のように二重引用符で囲みます。
Feature-Policyの書式のまま書いても動きますか?
動きません。camera 'none'; microphone 'none' のような旧Feature-Policyの書式は、Permissions-Policyの構文として解析できません。仕様では解析できない場合ポリシーは空として扱われるため、ヘッダー全体が無視されます。
Permissions-Policyを付けないと、カメラやマイクが勝手に使われますか?
いいえ。カメラ、マイク、位置情報の利用には別途ユーザーの許可ダイアログが必要です。Permissions-Policyは、許可を求めること自体をできなくする追加の制限で、注入されたスクリプトが公式サイトの名前で許可を求める状況を防ぎます。
すべての機能を列挙しないと意味がありませんか?
camera、microphone、geolocation、payment、usb などの主要な強力機能から始めれば十分効果があります。ブラウザが知らない機能名は無視されるため、コンソールに警告が出ることはありますが動作は壊れません。
fullscreen=()やautoplay=()も付けたほうがよいですか?
動画を埋め込むサイトでは外してください。fullscreen=() や autoplay=() を指定すると、埋め込み動画の全画面表示や自動再生ができなくなります。実際に使っている機能を棚卸ししてから決めます。
interest-cohort=()は必要ですか?
FLoC向けの指定で、現在は意味を持ちません。残っていても害はなく、セキュリティAIチェッカーの判定にも影響しません。
Permissions-Policyが未設定だとどう判定されますか?
「△ 要確認」(重み1の45%)です。構文として解釈できない記述がある場合や、camera・microphone・geolocation・paymentのいずれかを =* で全オリジンに許可している場合も△です。この項目では×と対象外は使いません。
この項目を含む127項目を、URLを入れるだけで無料診断します。