最新の安定バージョンについては、Spring Security 6.3.3 を使用してください! |
匿名認証
概要
一般に、許可するものと明示的に禁止するものを明示的に指定する「デフォルトで拒否」を採用することは、優れたセキュリティ慣行と考えられています。特に Web アプリケーションの場合、認証されていないユーザーがアクセスできるものを定義することも同様の状況です。多くのサイトでは、いくつかの URL 以外(ホームページやログインページなど)についてユーザーを認証する必要があります。この場合、すべての保護されたリソースに対してではなく、これらの特定の URL に対してアクセス構成属性を定義するのが最も簡単です。別の言い方をすると、ROLE_SOMETHING
がデフォルトで必要であり、アプリケーションのログイン、ログアウト、ホームページなど、このルールの特定の例外のみを許可すると言うのはいいことです。これらのページをフィルターチェーンから完全に省略して、アクセス制御チェックをバイパスすることもできますが、他の理由、特に認証されたユーザーに対してページの動作が異なる場合、これは望ましくない場合があります。
これが匿名認証の意味です。「匿名で認証された」ユーザーと認証されていないユーザーの間に実際の概念上の違いはないことに注意してください。Spring Security の匿名認証は、アクセス制御属性を構成するためのより便利な方法を提供します。たとえば、getCallerPrincipal
などのサーブレット API を呼び出すと、SecurityContextHolder
に実際には匿名の認証オブジェクトが存在する場合でも、null が返されます。
監査インターセプターが SecurityContextHolder
を照会して、特定の操作を担当したプリンシパルを識別する場合など、匿名認証が役立つ状況が他にもあります。SecurityContextHolder
が常に Authentication
オブジェクトを含み、決して null
を含まないことがわかっている場合、クラスをより堅牢に作成できます。
構成
匿名認証のサポートは、HTTP 構成 Spring Security 3.0 を使用すると自動的に提供され、<anonymous>
要素を使用してカスタマイズ(または無効化)できます。従来の Bean 構成を使用していない限り、ここで説明する Bean を構成する必要はありません。
匿名認証機能を一緒に提供する 3 つのクラス。AnonymousAuthenticationToken
は Authentication
の実装であり、匿名プリンシパルに適用される GrantedAuthority
を格納します。AnonymousAuthenticationToken
が受け入れられるように、ProviderManager
にチェーンされた対応する AnonymousAuthenticationProvider
があります。最後に、AnonymousAuthenticationFilter
があります。これは、通常の認証メカニズムの後にチェーンされ、既存の Authentication
が保持されていない場合、AnonymousAuthenticationToken
を SecurityContextHolder
に自動的に追加します。フィルターと認証プロバイダーの定義は次のように表示されます。
<bean id="anonymousAuthFilter"
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<property name="key" value="foobar"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
<bean id="anonymousAuthenticationProvider"
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>
key
はフィルターと認証プロバイダーの間で共有されるため、前者によって作成されたトークンは後者 [ 1 ] によって受け入れられます。userAttribute
は usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]
の形式で表現されます。これは、InMemoryDaoImpl
の userMap
プロパティの等号の後に使用されるものと同じ構文です。
前に説明したように、匿名認証の利点は、すべての URI パターンにセキュリティを適用できることです。例:
<bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
<property name="securityMetadata">
<security:filter-security-metadata-source>
<security:intercept-url pattern='/index.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/hello.htm' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/logoff.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/login.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/**' access='ROLE_USER'/>
</security:filter-security-metadata-source>" +
</property>
</bean>
AuthenticationTrustResolver
匿名認証の議論を締めくくるのは、AuthenticationTrustResolver
インターフェースとそれに対応する AuthenticationTrustResolverImpl
実装です。このインターフェースは isAnonymous(Authentication)
メソッドを提供します。これにより、関心のあるクラスはこの特別な型の認証ステータスを考慮することができます。ExceptionTranslationFilter
は、AccessDeniedException
の処理にこのインターフェースを使用します。AccessDeniedException
がスローされ、認証が匿名型の場合、403(禁止)レスポンスをスローする代わりに、フィルターは代わりに AuthenticationEntryPoint
を開始し、プリンシパルが正しく認証できるようにします。これは必要な区別です。そうでなければ、プリンシパルは常に「認証済み」とみなされ、フォーム、基本、ダイジェスト、その他の通常の認証メカニズムを介してログインする機会が与えられません。
上記のインターセプター構成の ROLE_ANONYMOUS
属性が IS_AUTHENTICATED_ANONYMOUSLY
に置き換えられていることがよくあります。これは、アクセス制御を定義する場合と実質的に同じです。これは、認証の章で説明する AuthenticatedVoter
の使用例です。AuthenticationTrustResolver
を使用して、この特定の構成属性を処理し、匿名ユーザーにアクセスを認可します。AuthenticatedVoter
アプローチは、匿名、remember-me、完全に認証されたユーザーを区別できるため、より強力です。ただし、この機能が必要ない場合は、ROLE_ANONYMOUS
を使用できます。これは、Spring Security の標準 RoleVoter
によって処理されます。
Spring MVC を使用した匿名認証の取得
独自の引数リゾルバーを使用する Spring MVC は、型 Principal
のパラメーターを解決します。
これは、次のような構成を意味します。
Java
Kotlin
@GetMapping("/")
public String method(Authentication authentication) {
if (authentication instanceof AnonymousAuthenticationToken) {
return "anonymous";
} else {
return "not anonymous";
}
}
@GetMapping("/")
fun method(authentication: Authentication?): String {
return if (authentication is AnonymousAuthenticationToken) {
"anonymous"
} else {
"not anonymous"
}
}
匿名のリクエストであっても、常に「匿名ではない」を返します。その理由は、Spring MVC が HttpServletRequest#getPrincipal
を使用してパラメーターを解決するためです。HttpServletRequest#getPrincipal
は、リクエストが匿名の場合は null
です。
匿名リクエストで Authentication
を取得する場合は、代わりに @CurrentSecurityContext
を使用してください。
Java
Kotlin
@GetMapping("/")
public String method(@CurrentSecurityContext SecurityContext context) {
return context.getAuthentication().getName();
}
@GetMapping("/")
fun method(@CurrentSecurityContext context : SecurityContext) : String =
context!!.authentication!!.name
key
プロパティの使用は、ここで実際のセキュリティを提供するものと見なされるべきではありません。これは単なる記録管理の練習です。認証クライアントが Authentication
オブジェクトを構築することが可能なシナリオ(RMI 呼び出しなど)で AnonymousAuthenticationProvider
を含む ProviderManager
を共有している場合、悪意のあるクライアントは自身で作成した AnonymousAuthenticationToken
を送信できます(選択された状態で)ユーザー名と権限リスト)。key
が推測可能である場合、または見つけられる場合、トークンは匿名プロバイダーによって受け入れられます。これは通常の使用では問題ありませんが、RMI を使用している場合は、HTTP 認証メカニズムに使用するプロバイダーを共有するのではなく、匿名プロバイダーを省略するカスタマイズされた ProviderManager
を使用するのが最善です。