【Chrome】いちど拒否した位置情報やカメラの権限を何度も何度も何度も何度も何度も何度も何度も何度も要求できるようになる

現在のブラウザは、いちどカメラやPUSH通知の権限要求を拒否すると、その後要求プロンプトを出すことができません。
Webサイトができることは、『〇〇を許可してください』とウィンドウを出すことくらいです。

↓人類史上最悪の許可要求ウィンドウの例
![51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/cfee9c61-7310-c773-68b4-473752d781ee.png)

この後設定欄から各機能を有効化するためには、ユーザによる絶対的能動的な操作が必要となります。

また、プライバシーとセキュリティ設定から許可しない設定をしておくと、たったの一度すらもチャンスが与えられず、一生権限を要求することはできません。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/979472b6-0959-e8ae-c669-c05efeea926e.png)

結果としてPUSH通知の権限要求などは、9割以上のユーザが拒否するという当然の事態になっています。

ということで、一度拒否したとしても権限を再度要求できるようにする動きが水面下で画策されています。
以下は該当の提案、[Page Embedded Permission Control (PEPC)](https://github.com/WICG/PEPC/blob/main/explainer.md)のざっくり紹介です。


# Page Embedded Permission Control (PEPC)

## Introduction

あるWebサイトが強力な機能を必要とする場合、ユーザエージェントは通常、その許可をユーザに求めます。
歴史的には、これはかなり直接的な形で行われてきました。
すなわち、サイトが何らかの機能を要求すると、ユーザエージェントは即座にプロンプトを表示して、ユーザに要求を認めるよう求めます。

スパムや不正使用に濫用された結果、ユーザのセキュリティ・プライバシー保護のため、より保守的なアプローチを取らざるを得なくなりました。
[権限プロンプトを出すためにユーザの操作を必要とする](https://developer.mozilla.org/en-US/docs/Web/Security/User_activation)、永続的ブロック、[ヒューリスティック検出](https://blog.google/products/chrome/building-a-more-helpful-browser-with-machine-learning/)など、様々な緩和策が開発されてきました。

しかし、これらの対策の効果は指標が示すように限定的です。
現状は以下のような課題があります。

既存の緩和策は不十分。
現在の権限スパムや不正使用緩和アプローチでは、ユーザ保護に構造的な限界があります。
これはユーザが権限を必要とするタイミングをキャプチャするのではなく、Webサイトが権限要求プロンプトを表示するタイミングをキャプチャしているためです。
許可を求めるために[ユーザのジェスチャを必要とした](https://www.w3.org/TR/permissions/#dfn-request-permission-to-use)としても、この問題は解決しません。
マウスクリックやキー入力など、ユーザをだましてジェスチャーを実行させる方法は数多く存在するからです。

コンテキスト。
理想としては、Webサイトの開発者はコンテキストフローの一部としてアクセスを要求します。
これによって、ユーザは要求の内容とその理由を理解し、迅速かつ確信をもってアクセス要求に対応できるようになります。
しかし現在、アクセス要求は多くの場合ユーザの期待するタイミングとあまり関連しておらず、プロンプトが突然脈絡なく表示されます。

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/a3802c21-15d4-3075-fb2f-d7941f3ffcd5.png)

これはとあるニュースサイトの通知許可プロンプトです。
ユーザがコンテンツの横の空白をクリックした際に現れます。
ユーザは通知に興味がないのでプロンプトを邪魔だと感じるし、そもそもなぜプロンプトが表示されたかの説明もないので理解にも苦しみます。

理想的なケースでは、ユーザはサイト上でその機能が欲しいと思ったのでプロンプトをトリガーする操作を行います。
理想的でないケースでは、ユーザはサイト上で特に何もしていないか、何の関係もない操作でプロンプトがトリガーされます。
ユーザエージェントは通常、ページの左上など許可プロンプトを固定の位置に表示します。
理想的な場合でも、ユーザがクリックしたところと全く異なるところに許可プロンプトが現れるため、注意を払う位置を移動しなければならないという残念な結果をもたらします。
ユーザが現在注目している領域をユーザエージェントが理解すれば、より適切なプロンプトを表示することができます。

![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/e0b2e8b4-536c-2160-7193-0c952baa26d3.png)

権限プロンプトが、ユーザのフォーカスから遠く離れている例。
ユーザが右下の十字アイコンをクリックした際に権限プロンプトが現れましたが、クリックした地点と遠く離れているため見逃しやすいです。

復活のしづらさ。
一度ブロックしたあと、同じWebサイトから同じ権限要求があった際にユーザエージェントが要求を抑制するのは合理的です。
しかしユーザの考えが変わって権限を許可したくなったときにもWebサイトは権限要求を出すことができず、ユーザが権限を許可することに失敗することがよくあります。

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/183c5243-3545-1e47-5729-d98c853930b5.png)

ユーザは以前カメラとマイクの権限要求を拒否したが、ミュート解除ボタンを押して再度有効にしたいという意志を示した例。
ユーザエージェントはユーザのかつての意思を尊重してブロックせざるを得ず、ユーザは解除方法を見つけることが難しい。

アクセシビリティ。
ユーザエージェントは、セキュリティ上の理由からユーザが拡大鏡を使っているかどうかを検知することはできません。
拡大鏡を使っている場合、権限プロンプトが画面外に表示されることがあり、ユーザはそれに気付くことができません。

現状を改善するには、ユーザエージェントが、ユーザが権限を欲しているという意図的な信号をコンテンツから抽出できるようにする必要があります。
これによって、機能へのアクセスがユーザの意志によって行われているのだということを明確に受け取ることができるようになります。
これは、ユーザによる以前の永続的なブロックの決定を尊重しながら、ユーザが考えを変えられるようにしたい場合に特に重要です。

## Proposal

Webプラットフォームに、新しいHTML要素`<permission>`を提案します。
この要素は、権限の認可要求を提供するエントリポイントとして機能します。

このHTML要素はbuttonのように見え、他のHTML要素と同じように使用できます。
異なるのは、このボタンが反応したときに、ユーザが意思を持ってこのボタンをクリックしたとユーザエージェントが確信できることです。
この要素はクリックジャッキングなどの不正使用パターンからユーザを保護する手段が備えられます。
我々はこれをページ埋め込み権限制御"Page Embedded Permission Control"、略称PEPCと名付けました。

ベストプラクティスに従う開発者は、オンボーディングエクスペリエンスの一部として許可フローを実装します。

![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/29d5a937-1266-9b2b-e0ab-2e08e308ae47.png)


ビデオ会議サイトの例。
"Enable camera"ボタンを押すと、ユーザエージェントによるカメラの許可プロンプトが表示される。

![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/d24c723b-b951-febd-1785-015063be417d.png)

メッセージングサイトの例。
"Enable Desktop Notifications"ボタンを押すと、ユーザエージェントによるPUSH通知の許可プロンプトが表示される。

このような開発者主導のアプローチをWeb標準に組み込むことで、Web全体として一貫したより優れた許可要求フローを実現できます。
ユーザーと開発者の両方に、次のような魅力的な利点を提供します。

・中断されない。
・位置を調整可能で、視点を遠くにそらされることがなくなるので見つけやすい。
・コンテキスト情報を提供できる。
・前は拒否していたけどユーザの気が変わったときに決定を変更することができる。
・Webサイト側で一貫性のある要素を提供できる。


使用例です。

```html
<style>
  permission {
    background-color: blue;
    color: white;
    border-radius: 10px;
  }
</style>

<permission
  onpromptdismiss="showContextInfo()"
  type="microphone"
/>

<script>
  function showContextInfo() {
    /* 領域外を押してプロンプトを閉じたので、追加情報を出したりできる */
  }
  navigator.permissions
    .query({ name: 'microphone' })
    .then((permissionStatus) => {
      permissionStatus.onchange = () => {
        /* ステータスの変更を感知した */
        if (permissionStatus.state === 'granted') startUsingMic();
      };
      /* 初回起動 */
      if (permissionStatus.state === 'granted') startUsingMic();
    });
</script>
```

![23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/0762dc87-d5bc-28c8-9ffb-2913f36abae7.png)


開発者は、権限要求プロンプトの色や境界線のスタイルをある程度設定できます。
権限要素をクリックすると、ユーザエージェントによって権限プロンプトが表示されます。

![24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/6b34a26b-e300-7c36-71cf-ddd4979e122f.png)

## Goals & non-goals

この提案の目的は、権限要求フローを改善する手段としてPEPCを提供し、ユーザエージェントが考慮すべきセキュリティ問題とオプションのリストを提供することです。

PEPCはWebサイトとシームレスに統合される必要がありますが、サイトが簡単に悪用できてもいけません。
PEPCはユーザが何らかの権限を使用を開始する意図を示したものなので、ユーザエージェントはより情報に基づいた権限要求の提示方法を提供することができます。

長期的にPEPCは、ユーザに最高のエクスペリエンスを提供し、開発者の負担を簡素化するため、サイトが権限要求を行うデフォルトのソリューションになるはずです。
PEPCがユースケースに適合しない場合は、これまでのJSのみのAPIを引き続き使用可能です。

## Adoption

PEPCは、既存の権限要求フローすべてに成り代わるものではありません。
現実的にメリットのある権限要求リクエストの大部分は、比較的少数のサイトが占めています。
たとえばカメラ・マイクを必要とするビデオ会議やチャットアプリなど、位置情報による店舗検索機能を備えたeコマースサイトなどです。

## Design considerations

### HTML element

#### Usage

PEPCはWebサイトと視覚的に統合される必要があるため、通常のボタン同様CSSでスタイル設定することができます。

```html
<style>
  permission {
    background-color: lightgray;
    color: black;
    border-radius: 10px;
  }
</style>
<permission type="geolocation" />
```

![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/5d3fd5f4-fb7b-91de-fbb2-b0c695280df1.png)

PEPCはユーザエージェントが解釈するものであり、子要素を持ちません。
権限が付与されると、ユーザエージェントはこれをユーザに伝えるために画面表示を変更する必要があります。

```html
<style>
  permission {
    background-color: lightgray;
    color: black;
    border-radius: 10px;
  }
  permission:granted {
    background-color: white;
    color: blue;
  }
</style>
<permission type="geolocation" />
```

![31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/5d3fd5f4-fb7b-91de-fbb2-b0c695280df1.png)

権限がない場合の表示。

![32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/54951e46-b3e7-e2b8-25d3-1408a67213a6.png)

権限が既に付与されている場合の表示。

また、サイト上では権限が付与された場合にPEPCのスタイルを変更したいことがあるので、その場合は疑似クラス`:granted`が使用可能です。

権限ステータスを変更したイベントは[GlobalEventHandlers](https://html.spec.whatwg.org/#globaleventhandlers)に追加されます。
これらはバブリングせず、キャンセルもできません。

・onpromptdismiss：権限UIが、×ボタンやUI外部クリックなどで閉じられたときに発動。
・onpromptaction：ユーザが権限UIで何らかのボタンを押した。必ずしも変更されるわけではなく、許可を継続する場合にも発動する。
・onvalidationstatuschange：PEPCが有効から無効に切り替わった。Securityセクションで詳しく解説。

実装例です。

```html
<permission type="geolocation" onpromptdismiss="showLocationWarning()" />
<script>
  function showLocationWarning() {
    // たとえば「この機能を使うには位置情報が必要です」みたいなコンテキストを提供できる
  }

  // 権限要求する
  navigator.permissions.query({name: "geolocation"})
    .then((permissionStatus) => {
      permissionStatus.onchange = () => {
        // 許可されたときにトリガー
        if (permissionStatus.state === "granted")
          startFeatureX();
      };
      // 最初から許可されていた
      if (permissionStatus.state === "granted")
          startFeatureX();
    });
</script>
```

#### Restrictions

ユーザの明示的な意図なしに、サイトがPEPCを悪用してトリガーできないようにすることが重要です。
これは、ユーザが許可を求める意図を持っていることをユーザエージェントが確信できる必要があるためです。

### Permission UI

ユーザがPEPCをクリックした後に確認UIを表示するのはユーザエージェントの責任ですが、考慮すべき事項が幾つかあります。
ユーザエージェントは、現在の権限状態に基づいて、異なるUIを検討する必要があります。
ユーザエージェントは、PEPCを表示する位置に相対位置を検討する必要があります。

#### Standard UI

以下はPEPCをクリックした際に表示される可能性のある確認UIの例です。

![33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/a86bed28-16b2-d851-8cbf-8c6cbcd6af08.png)

#### UI when the user can't change the permission

多くのユーザエージェントは、管理者もしくは管理機能によって、ユーザによってオーバーライドできない権限機能を提供しています。
このような状況ではPEPCテキスト自体は変更せず、確認UIでその旨を表示する必要があります。

![34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/4b2b853a-8e1b-6031-9aa2-f24c7aec2e45.png)

#### UI when there is a mechanism that would block the request

上記のほかに、ユーザエージェントがパーミッションリクエストを防止するメカニズムはいくつもあります。
明示もしくは暗黙的な永続拒否、一定期間拒否、ヒューリスティック、ブロックリスト、機械学習による自動ブロックなどです。
PEPCとこれらのメカニズムのどちらが優先されるかは検討する必要があります。
ユーザエージェントはそれぞれ独自のメカニズムがあり、適切な許可UXの目標も異なるため、ここで詳細を決定することはできません。

たとえば権限を既に拒否しているが、ユーザがPEPCをクリックした際の確認UIは次のようになります。

![35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/23d27c42-288a-6bf3-4b7f-9ee079ef0e91.png)

#### UI when the permission is already granted

権限が既に付与されている場合、PEPCテキストも合わせて変更されます。
ユーザがこの状態でPEPCをクリックした場合、権限UIにはあまり意味がありません。

![36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/2a6577af-2e52-d580-e83d-6d433e29f4eb.png)

## Security

### Threat model

ユーザエージェントの目標は、PEPCが悪用されやすいものではないことです。
悪用方法は主に2種類であり、安全性とユーザへの煩わしさです

#### Safety

PEPCの安全性は、ユーザが許可を与える決定を確認するために使用される許可プロンプト、確認UIにかかっています。
確認UIは、既存の非モーダル許可プロンプトよりもはるかに優れています。
理由は以下のとおりです。

・ブラウザによって生成され、Webサイトは既定の許可タイプを要求することしかできません。
・確認UIの裏のWebサイトコンテンツは霞んで表示されるため、サイトがユーザの意思決定を操作したり、確認UIを難読化することはできません。

#### Annoyance

煩わしさを軽減することは、PEPCの安全性を確保することよりも複雑ですが、提案の目的としては同様に重要です。

Webサイトはモーダルを繰り返しトリガーしてユーザを煩わせることができます。

サイトは、誤解を招くテキスト(続行するにはここをクリックしてくださいなど)を表示してユーザを騙すことができます。
従って、PEPCのテキストはユーザエージェントが用意し、Webサイトから指定することはできません。

Webサイトは、CSSによってテキストを読みづらくしたりする可能性があります。
従って、ユーザエージェントは必要に応じてスタイルを検証・オーバーライドする必要があります。

Webサイトは、別のHTML要素によってPEPCを隠そうとする可能性があります。
従って、ユーザエージェントはPEPCが直近でしばらく画面い表示されていたことを確認する必要があります。

Webサイトは、ユーザがクリックしようとした場所にPEPCの許可ボタンを移動して許可クリックを取得しようとする可能性があります。
従って、ユーザエージェントはPEPCが直近で移動されていないことを確認する必要があります。

Webサイトは、ユーザがクリックしようとした場所にPEPCの許可UIを表示して許可クリックを取得しようとする可能性があります。
従って、ユーザエージェントはPEPCが直近でDOMに挿入されていないことを確認する必要があります。


### Locking the PEPC style

ユーザエージェントは、PEPCのスタイルを限定する必要があります。
これにより、悪意のある人物がユーザを騙すクリックジャッキングやソーシャルエンジニアリング攻撃からユーザを保護します。

以下は限定すべきCSSプロパティのリストです。

・letter-spacing：0.2emを超える場合は0.2emに、-0.05em未満の場合は-0.05emに修正される。
・display：'inline-block'と'none'のみ可能。他は全て'inline-block'にされる。

他にもたくさんあるけど省略。


### One PEPC per permission type per page

WebサイトがPEPCで画面を埋め尽くすことを防ぐため、1つのページが要求できる権限タイプは2個に限定されます。
制限数が2である理由は、PEPCを必要とする正当な使用例をサポートするためです。

### Conditions for usage in subframes

サブフレームでの使用は許可されます。

### Synthetic click events

onclickやonmousedownのようなイベントハンドラは、期待通りに動作します。


## Privacy

### Exposing user information bits

Webサイトが知ることができる情報は、Webサイトが知る必要のある情報に限定される必要があります。
Permissions API経由で知ることができる情報などはPEPC経由で公開しても問題ありません。

たとえば管理者がユーザに替わって特定の権限を管理している場合、ユーザエージェントはPEPCのテキストに『管理者によってブロックされています』と表示することができます。
しかし、これによってWebサイトは、ブラウザが管理者によって制御されているという通常知りえない情報を知ることができます。


## Alternatives considered

検討された代替案。

### No platform changes

変更しない。

現在、Webサイトは権限要求をトリガーするタイミングを調節することで、本提案の動作のほとんどを再現することができます。
ドキュメントやコミュニケーションを通じて、開発者にそのパターンを使用するよう働きかける必要があります。

しかし、ユーザが意図的に権限要求をトリガーしたことを示すシグナルは相変わらずありません。
すなわち、ユーザエージェントは依然として権限要求に対して防御的な態度である必要があります。

Webサイトはユーザエクスペリエンスをしっかり考えた設計が必要ですが、適切でない方法で実装している場合が多々あります。

### Separate this into two proposals, (1) improved user intent signal and (2) permission prompt improvements


ユーザの意図を示す提案と、許可プロンプトの改善の2つの提案に分ける。

それぞれが関連しているため分けることは難しい。

### Extending an existing element

既存要素の拡張。

新しいタグを追加するかわりに、inputなど既存の要素を拡張します。

```html
<p>
  Button:
  <button permission-type="geolocation"></button>
</p>
```

未対応のユーザエージェントでは何も動かないボタン要素がレンダリングされるだけであり、他のソリューションで補ったりしないかぎり、ユーザエクスペリエンスが悪化します。
PEPCと通常のボタンは機能が大きく異なるので、それぞれ別の要素にすることが理にかなっています。

### Providing a registration JS API

JavaScriptで提供する。

```js
<button id="pepc">Share location</button>

<script>
  pepc_params = {};
  pepc_params['type'] = 'geolocation';
  navigator.permissions.registerPEPC(
    document.getElementById('pepc'),
    pepc_params,
  );
</script>
```

該当の要素がPEPCであるかそうでないかがわからないため、セキュリティ上の検証・制約が困難になります。
ひとつの要素は常にPEPCであるかそうでないかのどちらかであるほうが安全です。

### Extending the Permissions API to provide an anchor point

既存のPermissions APIを拡張する。

```html
<p id="pepc_anchor">This is where the permission prompt will be anchored</p>

<script>
  navigator.permissions.request(
    { name: 'geolocation' },
    document.getElementById('pepc_anchor'),
  );
</script>
```

ユーザの意図を示すシグナルがないため、悪意のあるサイトが許可プロンプトを悪用しやすくなります。

### Allowing recovery via the regular permission flow

既存のPermissions APIで拒否を解除できるようにする。

既存のPermissions APIで、パーミッションをブロックされた状態から許可できるように変更することが考えられます。
悪意のあるWebサイトからユーザを保護することが困難です。

### Implementing an origin based permission allow list registry

許可リストレジストリの作成。

適切に動作するオリジンは、Permissions APIで拒否を解除できるようにする。

オリジン数は膨大であるため、まともにレビューはできない。
本来適切でありベストプラクティスを実装しているWebサイトも、永遠に待たされる可能性がある。


## Extending the PEPC in the future

将来の展望。
この提案には含まれていません。

### PEPC for additional user agent settings

一部のユーザエージェントは、OSログイン時に実行などのインストール可能なWebアプリ機能をサポートしています。
将来的に、インストールされたWebアプリの動作に関する設定をPEPCで制御できるようになります。

### Not "just" a button

現在の提案は、ボタンに似たHTML要素を想定しています。
権限要求に基いて、チェックボックスやその他の形式でのUIのPEPCを提供する可能性もあります。




# 感想

[『許可を停止』](https://developer.chrome.com/blog/permission-element-origin-trial?hl=ja#behavior)なんてウィンドウ誰も出すわけないだろ馬鹿か。

当然Webサイト側では、できるだけわかりにくいUIにしてユーザが気付かずに許可してしまうようあの手この手を尽くして騙してくるに決まっています。
提案では適用できるCSSを限定したりオーバレイを禁止したりして対応しようとしていますが、そんなのいくらでも抜け穴が見つかるでしょう。


# 動作デモ

まず最初に、あらゆるWebサイトに対してカメラの使用を禁止しておきます。
最初に言ったとおり、これはカメラの使用を禁止するだけではなく、カメラの使用の許可を求めることも禁止します。

![41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/9fa87d77-3f5a-6b1a-7d53-5c22fecacad4.png)


つぎに[デモページ](https://permission.site/pepc.html)にアクセスしましょう。

![42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/1a7ab6b1-7571-0cd7-a0c6-2ba042e86cb6.png)

ここから『カメラの使用』を選択すると、『引き続き禁止』『今回のみ許可』の選択ポップアップが現れます。

![43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/81debcc0-4c4d-dafe-3340-d0c43f497487.png)

では『今回のみ許可』を選んでみましょう。

![44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/4f0d1bbf-f225-fa97-f592-dd15f7254861.png)


(　ﾟдﾟ)

(　ﾟдﾟ)

( ﾟдﾟ )

(　ﾟдﾟ)


# PEPCを許可しない設定

PEPCを許可しない設定はありません。

<font color="red">**ありません。**</font>

これは私が勝手に言っているのではなく、[公式発言](https://docs.google.com/document/d/1pJFCADgasiqojESz2VePkVwaDdlfDqpN5JSqo4T4mMs/edit?hl=ja&tab=t.0)です。

:::note warn
Marian: No way to perma-block (dismiss by clicking out of the prompt area). 
[This raised some eyebrows.]

永久にブロックする方法はありません。プロンプト領域外をクリックして解除します。
(周囲ざわつく)
:::

# 他ブラウザの反応

こんな邪悪極まりないゴミクズゲロカス機能を他ブラウザがどう扱うかなんて、言うまでもないですよね。

当然ながら[Firefox](https://github.com/mozilla/standards-positions/issues/908)・[Safari](https://github.com/WebKit/standards-positions/issues/270)ともに反対であり、現在の仕様のままでChromium以外に実装される可能性は一切ありません。

本提案は、いつもどおりのChrome独自実装になります。


# その他

きっとAdBlockあたりが`<permission>`タグ自体を消去するよう対応してくれるはず。