Azure AD レガシー認証の見つけ方・やめ方(2)

皆さんこんにちは。国井です。

前回、Azure AD レガシー認証の見つけ方・やめ方(1)という投稿をしましたが、その続きです。前回はレガシー認証を見つけるときにはAzure ADのサインインログにフィルターをかけてレガシー認証のログだけが表示されるようにしましょうという話をしました。そして、その中でExchange ActiveSyncとアプリケーションパスワードを使った認証が多いという話をしました。
しかし、Exchange ActiveSyncとアプリケーションパスワードを使った認証が多いのは私が面倒を見ている環境の話であって、ほかの企業ではそうでもないかもしれません。
そこでレガシー認証の種類として何が使われているか、調べる方法について深掘りしてみたいと思います。

Log Analyticsを利用してレガシー認証を見つける

Log AnalyticsはMicrosoft Azureのサービスで、様々なログの格納とクエリによる分析ができます。Azure ADサインインのログをLog Analyticsへ持っていくと、そこからクエリを実行することで様々な分析ができます。Microsoft Azureの契約は必要になりますけど、クラウドなのでとりあえず使ってみて「やっぱり要らない」ということであれば削除しちゃえば良いのです。では設定していきましょう。

まず、Azure AD管理センターの [診断設定] メニューから診断設定を新規作成します。
このとき、logの種類としてSigninLogs、宛先としてLog Analyticsへの送信をそれぞれ選択します。
(※宛先としてLog Analyticsを選択するときは、Microsoft Azureの契約を済ませていること、そしてLog Analyticsのワークスペースを作成しておくことが前提条件になります)

image

設定が完了したら、しばらくするとLog Analyticsに保存されたデータからクエリを実行して分析を始められます。Log AnalyticsのクエリにはKQLと呼ばれる書式のクエリを使いますが、とりあえず使い始めたい人にはクエリを知らなくても使えるAzure AD管理センターの[Workbooks]メニューがおすすめです。

image

最初から色々なクエリが入ったレポートが用意されているので、クリックするだけで使えます。例えば、[レガシ認証を使用したサインイン]をクリックするとレガシー認証の構成要素が確認できます。今見ている環境ではExchange ActiveSyncを使ったアクセスとPOP3を使ったアクセスがそれぞれあることがわかります。

image

せっかくOffice 365 E3を買ってあげてるのに誰だよ、Outlook使わない人は.. というときはPOP3の項目をクリックします。すると、画面右側にユーザーと(ざっくりとした)アクセス日時が確認できます。

image

上の画面の右上にLog Analyticsボタンがありますが、これをクリックするとレポートに出ている内容をLog Analytics画面でクエリを実行した結果を表示してくれます。

image

POP3ユーザーが使っているアプリを特定したいと思ったらuserAgentを参照すればよいと思いつく方もいると思います。その場合、もともとのクエリがこちらですが、

let details = dynamic(
{
"Id":"Office 365 Exchange Online/POP3","Name":"POP3","Type":"Protocol","Sign-in Count":9,"Trend":"[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,2,1,0,0,2,1,0,1,0]","Failure Count":0,"User Interrupted Count":0,"ParentId":"Office 365 Exchange Online"});
let data = SigninLogs
|where AppDisplayName in ('*') or '*' in ('*')
|where UserDisplayName in ('*') or '*' in ('*')
|extend errorCode = toint(Status.errorCode)
|extend SigninStatus = case(errorCode == 0, "Success", errorCode == 50058, "Interrupt", errorCode == 50140, "Interrupt", errorCode == 51006, "Interrupt", errorCode == 50059, "Interrupt", errorCode == 65001, "Interrupt", errorCode == 52004, "Interrupt", errorCode == 50055, "Interrupt", errorCode == 50144, "Interrupt", errorCode == 50072, "Interrupt", errorCode == 50074, "Interrupt", errorCode == 16000, "Interrupt", errorCode == 16001, "Interrupt", errorCode == 16003, "Interrupt", errorCode == 50127, "Interrupt", errorCode == 50125, "Interrupt", errorCode == 50129, "Interrupt", errorCode == 50143, "Interrupt", errorCode == 81010, "Interrupt", errorCode == 81014, "Interrupt", errorCode == 81012 ,"Interrupt", "Failure")
|where SigninStatus == '*' or '*' == '*' or '*' == 'All Sign-ins'
|extend Reason = tostring(Status.failureReason)
|extend ClientAppUsed = iff(isempty(ClientAppUsed)==true,"Unknown" ,ClientAppUsed)
|extend isLegacyAuth = case(ClientAppUsed contains "Browser", "No", ClientAppUsed contains "Mobile Apps and Desktop clients", "No", ClientAppUsed contains "Exchange ActiveSync", "Yes", ClientAppUsed contains "Unknown", "Unknown", "Yes")
|where isLegacyAuth=="Yes"
| where AppDisplayName in ('*') or '*' in ('*')
| where details.Type == '*' or (details.Type == 'App' and AppDisplayName == details.Name) or (details.Type == 'Protocol' and AppDisplayName == details.ParentId and ClientAppUsed == details.Name);
data
| top 200 by TimeGenerated desc
| extend TimeFromNow = now() - TimeGenerated
| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')
| project User = UserDisplayName, ['Sign-in Status'] = strcat(iff(SigninStatus == 'Success', '', ''), ' ', SigninStatus), ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = errorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName

最終行の | project で始まる部分がクエリの結果として何を表示するか(SQLでいうSELECTの部分です)を表すところなので、これをカスタマイズして

| project User = UserDisplayName, [‘userAgent’] = UserAgent

と変更してみると

image

ご覧のような結果が出てきました。だけどBAV2ROPCってなに??
(ちなみにIMAP4アクセスだとCBAInPRODってログがでます)
あまり役に立たなかったですね..

あとは最初に登場したクエリの最後の行に

| where SigninStatus != ‘Success’

と入れておけば成功しなかったログを検索できます。
POP3/IMAP4を使った不正アクセスって最近多いと聞きますが、こうした不正アクセスの試行があったかを確認するのにも使えます。

その他、AuthenticationDetails 内のauthenticationMethod項目を使えば、アプリケーションパスワードを表すCloudOnlyPasswordの文字列が書いてあるので、
それを使ってアプリケーションパスワードの利用状況を調べたりできます。

条件付きアクセスを使う

Azure ADの条件付きアクセスで [レポート専用] というモードがあります。これを使って、以下のようなレガシー認証をブロックするような条件付きアクセスポリシーを設定してあげると

image

実際のブロックはせず、ログに「[レポート専用]ではなく、[オン]にしていたらブロックしていたよ」という報告を挙げてくれます。
ただし、「ブロックしていたよ」という一覧だけを抽出して参照する、というのが難しいんですよね。なので、こういうときもLog Analyticsを使って見てみましょう。

Azure AD管理センターの[Workbooks]メニューから[条件付きアクセスに関する分析情報とレポート]レポートを開いて、事前に作成した条件付きアクセスポリシーでフィルターをかけます。すると、直近24時間で3つのFailureのイベントがあることがわかります。

image

さらにFailureをクリックすると、画面下部にはFailureとなったサインインイベントの詳細が確認できます。

image

以上の内容から2021年のレガシー認証廃止に向けて対処しなければならないイベント/ユーザーが確認できます。

iOSデバイスでレガシー認証をやめる

前回、iOSの標準メーラーでもレガシー認証になるという話を書いたら、こんなコメントをいただきました。

iOS12以降はOAuth対応なんだけど、前のバージョンのiOSのメールプロファイルをそのまま使っている場合、iOSが12になっただけではOAuthにならないのです。そのため、iOS12以上のバージョンになったならば、メールプロファイルは一度作り直しが必要になります。そうしないといつまでもレガシー認証を使い続けることになります。
なので、まずはみんなが使っているiPhoneのiOSバージョンを確認し、iOS12以上になっているなら地道にアナウンスしていく、サポートが対応していくなどを行っていきます。
前に登場したレガシー認証のクエリでUserAgentが表示されるように設定すると

image

ご覧のようにiPhone/iPadのバージョンと、iOSのバージョンが表示されます。
スラッシュのあとにある番号がiOSのバージョンで、1600以降がiOS12以上になります。

■ ■ ■

こんな感じで調査してひとつずつレガシー認証を潰していく。地道ですけど、この手の作業を重ねて、ある日突然ブロックされないようにしたいものですね。

【参考】Log Analyticsを使えない/使いたくない人はExcelでもJSON形式でエクスポートしたデータをもとに分析できるよ、という話
https://jpazureid.github.io/blog/azure-active-directory/new-tools-to-block-legacy-auth/