How Does the Security access_control Work?

For each incoming request, Symfony checks each access_control entry to find one that matches the current request. As soon as it finds a matching access_control entry, it stops - only the first matching access_control is used to enforce access.

着信リクエストごとに、Symfony は各 access_control エントリをチェックして、現在のリクエストに一致するものを見つけます。一致する access_control エントリが見つかるとすぐに停止します。最初に一致する access_control のみがアクセスを強制するために使用されます。

Each access_control has several options that configure two different things:

各 access_control には、2 つの異なるものを構成するいくつかのオプションがあります。
  1. should the incoming request match this access control entry
    着信要求がこのアクセス制御エントリと一致する必要があります
  2. once it matches, should some sort of access restriction be enforced:
    一致したら、何らかのアクセス制限を適用する必要があります。

1. Matching Options

Symfony creates an instance of RequestMatcher for each access_control entry, which determines whether or not a given access control should be used on this request. The following access_control options are used for matching:

Symfony は各 access_control エントリに対して RequestMatcher のインスタンスを作成します。これは、このリクエストで特定のアクセス制御を使用する必要があるかどうかを決定します。マッチングには、次の access_controloptions が使用されます。
  • path: a regular expression (without delimiters)
    path: 正規表現 (区切り記号なし)
  • ip or ips: netmasks are also supported (can be a comma-separated string)
    ip または ips: ネットマスクもサポートされています (コンマ区切りの文字列にすることができます)
  • port: an integer
    ポート: 整数
  • host: a regular expression
    ホスト: 正規表現
  • methods: one or many HTTP methods
    メソッド: 1 つまたは複数の HTTP メソッド
  • request_matcher: a service implementing RequestMatcherInterface
    request_matcher: RequestMatcherInterface を実装するサービス
  • attributes: an array, which can be used to specify one or more request attributes that must match exactly
    attributes: 正確に一致する必要がある 1 つ以上のリクエスト属性を指定するために使用できる配列。
  • route: a route name
    route: ルート名

6.1

6.1

The request_matcher option was introduced in Symfony 6.1.

request_matcher オプションは Symfony 6.1 で導入されました。

6.2

6.2

The route and attributes options were introduced in Symfony 6.2.

ルートと属性のオプションは Symfony 6.2 で導入されました。

Take the following access_control entries as an example:

例として、次の access_control エントリを取り上げます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# config/packages/security.yaml
parameters:
    env(TRUSTED_IPS): '10.0.0.1, 10.0.0.2'

security:
    # ...
    access_control:
        - { path: '^/admin', roles: ROLE_USER_PORT, ip: 127.0.0.1, port: 8080 }
        - { path: '^/admin', roles: ROLE_USER_IP, ip: 127.0.0.1 }
        - { path: '^/admin', roles: ROLE_USER_HOST, host: symfony\.com$ }
        - { path: '^/admin', roles: ROLE_USER_METHOD, methods: [POST, PUT] }

        # ips can be comma-separated, which is especially useful when using env variables
        - { path: '^/admin', roles: ROLE_USER_IP, ips: '%env(TRUSTED_IPS)%' }
        - { path: '^/admin', roles: ROLE_USER_IP, ips: [127.0.0.1, ::1, '%env(TRUSTED_IPS)%'] }

        # for custom matching needs, use a request matcher service
        - { roles: ROLE_USER, request_matcher: App\Security\RequestMatcher\MyRequestMatcher }

        # require ROLE_ADMIN for 'admin' route. You can use the shortcut "route: "xxx", instead of "attributes": ["_route": "xxx"]
        - { attributes: {'_route': 'admin'}, roles: ROLE_ADMIN }
        - { route: 'admin', roles: ROLE_ADMIN }

For each incoming request, Symfony will decide which access_control to use based on the URI, the client's IP address, the incoming host name, and the request method. Remember, the first rule that matches is used, and if ip, port, host or method are not specified for an entry, that access_control will match any ip, port, host or method:

着信リクエストごとに、Symfony は URI、クライアントの IP アドレス、着信ホスト名、およびリクエスト メソッドに基づいて、どの access_control を使用するかを決定します。一致する最初のルールが使用され、ip、port、host、または method がエントリに指定されていない場合、access_control は任意の ip、port、host、または method と一致することに注意してください。
URI IP PORT HOST METHOD access_control Why?
/admin/user 127.0.0.1 80 example.com GET rule #2 (ROLE_USER_IP) The URI matches path and the IP matches ip.
/admin/user 127.0.0.1 80 symfony.com GET rule #2 (ROLE_USER_IP) The path and ip still match. This would also match the ROLE_USER_HOST entry, but only the first access_control match is used.
/admin/user 127.0.0.1 8080 symfony.com GET rule #1 (ROLE_USER_PORT) The path, ip and port match.
/admin/user 168.0.0.1 80 symfony.com GET rule #3 (ROLE_USER_HOST) The ip doesn't match the first rule, so the second rule (which matches) is used.
/admin/user 168.0.0.1 80 symfony.com POST rule #3 (ROLE_USER_HOST) The second rule still matches. This would also match the third rule (ROLE_USER_METHOD), but only the first matched access_control is used.
/admin/user 168.0.0.1 80 example.com POST rule #4 (ROLE_USER_METHOD) The ip and host don't match the first two entries, but the third - ROLE_USER_METHOD - matches and is used.
/foo 127.0.0.1 80 symfony.com POST matches no entries This doesn't match any access_control rules, since its URI doesn't match any of the path values.

Caution

注意

Matching the URI is done without $_GET parameters. Deny access in PHP code if you want to disallow access based on $_GET parameter values.

URI の照合は、$_GET パラメータなしで行われます。$_GET パラメータ値に基づいてアクセスを許可しない場合は、PHP コードでアクセスを拒否します。

2. Access Enforcement

Once Symfony has decided which access_control entry matches (if any), it then enforces access restrictions based on the roles, allow_if and requires_channel options:

Symfony がどの access_control エントリーに一致するか (もしあれば) を決定すると、ロール、allow_if および requires_channel オプションに基づいてアクセス制限を適用します。
  • roles If the user does not have the given role, then access is denied (internally, an AccessDeniedException is thrown).
    ユーザーが特定の役割を持っていない場合、アクセスは拒否されます (内部的に、AccessDeniedException がスローされます)。
  • allow_if If the expression returns false, then access is denied;
    allow_if 式が false を返す場合、アクセスは拒否されます。
  • requires_channel If the incoming request's channel (e.g. http) does not match this value (e.g. https), the user will be redirected (e.g. redirected from http to https, or vice versa).
    requires_channel 着信要求のチャネル (例: http) がこの値 (例: https) と一致しない場合、ユーザーはリダイレクトされます (例: http から https へ、またはその逆)。

Tip

ヒント

Behind the scenes, the array value of roles is passed as the $attributes argument to each voter in the application with the Request as $subject. You can learn how to use your custom attributes by reading How to Use Voters to Check User Permissions.

バックグラウンドで、ロールの配列値は $attributes 引数としてアプリケーション内の各投票者に渡され、リクエストは $subject として渡されます。カスタム属性の使用方法については、投票者を使用してユーザー権限を確認する方法を参照してください。

Caution

注意

If you define both roles and allow_if, and your Access Decision Strategy is the default one (affirmative), then the user will be granted access if there's at least one valid condition. If this behavior doesn't fit your needs, change the Access Decision Strategy.

ロールと allow_if の両方を定義し、Access DecisionStrategy がデフォルト (肯定) の場合、少なくとも 1 つの有効な条件があれば、ユーザーはアクセスを許可されます。この動作がニーズに合わない場合は、アクセス決定戦略を変更してください。

Tip

ヒント

If access is denied, the system will try to authenticate the user if not already (e.g. redirect the user to the login page). If the user is already logged in, the 403 "access denied" error page will be shown. See How to Customize Error Pages for more information.

アクセスが拒否された場合、システムはユーザーを認証しようとします (たとえば、ユーザーをログイン ページにリダイレクトします)。ユーザーがすでにログインしている場合は、403「アクセスが拒否されました」というエラー ページが表示されます。詳細については、エラー ページをカスタマイズする方法を参照してください。

Matching access_control By IP

Certain situations may arise when you need to have an access_control entry that only matches requests coming from some IP address or range. For example, this could be used to deny access to a URL pattern to all requests except those from a trusted, internal server.

特定の IP アドレスまたは範囲からのリクエストのみに一致する access_control エントリが必要な場合、特定の状況が発生する可能性があります。

Caution

注意

As you'll read in the explanation below the example, the ips option does not restrict to a specific IP address. Instead, using the ips key means that the access_control entry will only match this IP address, and users accessing it from a different IP address will continue down the access_control list.

例の下の説明を読むとわかるように、ips オプションは特定の IP アドレスに制限されません。代わりに、ipskey を使用すると、access_control エントリはこの IP アドレスにのみ一致し、別の IP アドレスからそれにアクセスするユーザーは access_control リストを下に進みます。

Here is an example of how you configure some example /internal* URL pattern so that it is only accessible by requests from the local server itself:

ローカル サーバー自体からの要求によってのみアクセスできるように、いくつかのサンプル /internal* URLpattern を構成する方法の例を次に示します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
# config/packages/security.yaml
security:
    # ...
    access_control:
        #
        # the 'ips' option supports IP addresses and subnet masks
        - { path: '^/internal', roles: PUBLIC_ACCESS, ips: [127.0.0.1, ::1, 192.168.0.1/24] }
        - { path: '^/internal', roles: ROLE_NO_ACCESS }

Here is how it works when the path is /internal/something coming from the external IP address 10.0.0.1:

パスが外部 IP アドレス 10.0.0.1 からの /internal/something である場合の動作は次のとおりです。
  • The first access control rule is ignored as the path matches but the IP address does not match either of the IPs listed;
    最初のアクセス コントロール ルールはパスが一致するため無視されますが、IP アドレスはリストされている IP のいずれとも一致しません。
  • The second access control rule is enabled (the only restriction being the path) and so it matches. If you make sure that no users ever have ROLE_NO_ACCESS, then access is denied (ROLE_NO_ACCESS can be anything that does not match an existing role, it only serves as a trick to always deny access).
    2 番目のアクセス コントロール ルールが有効になっているため (唯一の制限はパスです)、一致します。 ROLE_NO_ACCESS を持つユーザーがいないことを確認すると、アクセスが拒否されます (ROLE_NO_ACCESS は、既存のロールと一致しないものであれば何でもかまいません。これは、常にアクセスを拒否するトリックとしてのみ機能します)。

But if the same request comes from 127.0.0.1 or ::1 (the IPv6 loopback address):

ただし、同じリクエストが 127.0.0.1 または ::1 (IPv6 ループバックアドレス) から送信された場合:
  • Now, the first access control rule is enabled as both the path and the ip match: access is allowed as the user always has the PUBLIC_ACCESS role.
    ここで、パスと IP の両方が一致するため、最初のアクセス制御ルールが有効になります。ユーザーは常に PUBLIC_ACCESS ロールを持っているため、アクセスが許可されます。
  • The second access rule is not examined as the first rule matched.
    最初のルールが一致したため、2 番目のアクセス ルールは検査されません。

Securing by an Expression

Once an access_control entry is matched, you can deny access via the roles key or use more complex logic with an expression in the allow_if key:

access_control エントリが一致すると、theroles キーを介してアクセスを拒否するか、allow_ifkey の式でより複雑なロジックを使用できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
# config/packages/security.yaml
security:
    # ...
    access_control:
        -
            path: ^/_internal/secure
            # the 'roles' and 'allow_if' options work like an OR expression, so
            # access is granted if the expression is TRUE or the user has ROLE_ADMIN
            roles: 'ROLE_ADMIN'
            allow_if: "'127.0.0.1' == request.getClientIp() or request.headers.has('X-Secure-Access')"

In this case, when the user tries to access any URL starting with /_internal/secure, they will only be granted access if the IP address is 127.0.0.1 or a secure header, or if the user has the ROLE_ADMIN role.

この場合、ユーザーが /_internal/secure で始まる URL にアクセスしようとすると、IP アドレスが 127.0.0.1 またはセキュア ヘッダーである場合、またはユーザーが ROLE_ADMIN ロールを持っている場合にのみアクセスが許可されます。

Note

ノート

Internally allow_if triggers the built-in ExpressionVoter as like it was part of the attributes defined in the roles option.

内部的に allow_if は、ロール オプションで定義された属性の一部であるかのように、組み込みの ExpressionVoteras をトリガーします。

Inside the expression, you have access to a number of different variables and functions including request, which is the Symfony Request object (see The HttpFoundation Component).

式の内部では、SymfonyRequest オブジェクトである request を含むさまざまな変数や関数にアクセスできます (HttpFoundation コンポーネントを参照)。

For a list of the other functions and variables, see functions and variables.

他の関数と変数のリストについては、関数と変数を参照してください。

Tip

ヒント

The allow_if expressions can also contain custom functions registered with expression providers.

allow_if 式には、式プロバイダーに登録されたカスタム関数を含めることもできます。

Restrict to a port

Add the port option to any access_control entries to require users to access those URLs via a specific port. This could be useful for example for localhost:8080.

port オプションを任意の access_control エントリに追加して、ユーザーが特定のポート経由でこれらの URL にアクセスすることを要求します。これは、たとえば localhost:8080 の場合に役立ちます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
# config/packages/security.yaml
security:
    # ...
    access_control:
        - { path: ^/cart/checkout, roles: PUBLIC_ACCESS, port: 8080 }

Forcing a Channel (http, https)

You can also require a user to access a URL via SSL; use the requires_channel argument in any access_control entries. If this access_control is matched and the request is using the http channel, the user will be redirected to https:

SSL 経由で URL にアクセスすることをユーザーに要求することもできます。すべての access_control エントリで requires_channel 引数を使用します。このaccess_control が一致し、リクエストが http チャネルを使用している場合、ユーザーは https にリダイレクトされます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
# config/packages/security.yaml
security:
    # ...
    access_control:
        - { path: ^/cart/checkout, roles: PUBLIC_ACCESS, requires_channel: https }