Skip to content

Commit 97132fa

Browse files
committed
[best practice] security.rst の翻訳
1 parent 4e225bd commit 97132fa

File tree

1 file changed

+359
-0
lines changed

1 file changed

+359
-0
lines changed

best_practices/security.rst

Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
セキュリティ
2+
========
3+
4+
認証とファイアウォール (i.e ユーザの権限情報を取得する)
5+
------------------------------------------------------------------
6+
7+
任意の方法を使用してユーザー認証を行い、
8+
任意のソースからユーザー情報を読み込むように Symfony を設定することができます。
9+
10+
セキュリティはとても難解なテーマですが、`Security Cookbook Section`_ に多くの情報が記載されています。
11+
12+
認証は、その必要性の有無に関わらず、
13+
``security.yml`` の ``firewalls`` キーの下に設定されています。
14+
15+
.. best-practice::
16+
17+
正規に許可された2つの異なる認証システムとユーザが無い限り
18+
(e.g. メインとなるサイトと API のためだけのトークンシステムのためのログイン)、
19+
``anonymous`` のキーを有効にしたたったひとつのファイヤーウォールを設けることを推奨します。
20+
21+
ほとんどのアプリケーションで認証システムとユーザのセットはひとつしかありません。
22+
このため、ひとつのファイヤーウォールの設定だけで事足ります。
23+
もちろん、サイトの API と WEB を分けたい場合などの例外もありますが、シンプルに考えていくことが重要です。
24+
25+
なお、ファイヤーウォールの下では ``anonymous`` キーを利用するべきです。
26+
サイトの異なるセクション (または 全てのセクションのようなもの) にユーザが
27+
ログインすることが必要となった場合は ``access_control`` エリアを利用します。
28+
29+
.. best-practice::
30+
31+
ユーザのパスワードのエンコーディングには ``bcrypt`` エンコーダーを利用する。
32+
33+
ユーザがパスワードを持つ場合、SHA-512 の代わりに ``bcrypt`` エンコーダーを利用することを推奨します。
34+
``bcrypt`` の主要なアドバンテージは、**ソルト** の値が有しているものが
35+
レインボーテーブルアタックから保護しブルートフォースアタックを遅延できることです。
36+
37+
この考えで、データベースからユーザをロードするログインフォームを利用する認証を
38+
アプリケーションにセットアップする設定は以下となります。
39+
40+
.. code-block:: yaml
41+
42+
security:
43+
encoders:
44+
AppBundle\Entity\User: bcrypt
45+
46+
providers:
47+
database_users:
48+
entity: { class: AppBundle:User, property: username }
49+
50+
firewalls:
51+
secured_area:
52+
pattern: ^/
53+
anonymous: true
54+
form_login:
55+
check_path: security_login_check
56+
login_path: security_login_form
57+
58+
logout:
59+
path: security_logout
60+
target: homepage
61+
62+
# ... access_control exists, but is not shown here
63+
64+
.. tip::
65+
66+
プロジェクトのソースコードにそれぞれの部位を説明するコメントをもつ。
67+
The source code for our project contains comments that explain each part.
68+
69+
70+
承認 (i.e. アクセスを拒否すること)
71+
-----------------------------------
72+
73+
Symfony は承認のためにいくつかの方法を提供しています。
74+
`security.yml`_ に ``access_control`` の設定を含めること、
75+
``security.context`` サービスに直接 `@Security annotation <best-practices-security-annotation>` と
76+
`isGranted <best-practices-directy-isGranted>` を使うという方法です。
77+
78+
.. best-practice::
79+
80+
* 広範囲の URL パターンをプロテクトするためには ``access_control`` を利用する。
81+
* いつでも可能なときは ``@Security`` アノテーションを利用する。
82+
* より複雑な状況の場合はいつでも、
83+
``security.context`` サービスでセキュリティを直接的にチェックする。
84+
85+
承認ロジックを一箇所に集中させるには
86+
カスタムセキュリティ Voter や ACL を利用するというような方法があります。
87+
88+
.. best-practice::
89+
90+
* きめ細かい制限のために、カスタムセキュリティ Voter を定義する。
91+
* 管理機能を経由したあらゆるユーザによる
92+
あらゆるのオブジェクトへのアクセスを制限するために Symfony ACL を利用する。
93+
94+
.. _best-practices-security-annotation:
95+
96+
@Security アノテーション
97+
------------------------
98+
99+
可能な限り、コントローラーごとにアクセスを制御するためには ``@Secury`` アノテーションを利用します。
100+
この記述は、可読性が高く、整合性を保ったままでそれぞれのアクションに設置することができます。
101+
102+
このアプリケーションでは、新しいポストを作成するための ``ROLE_ADMIN`` が必要です。
103+
``@Security`` を利用するとこのようになります。
104+
105+
.. code-block:: php
106+
107+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
108+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
109+
// ...
110+
111+
/**
112+
* Displays a form to create a new Post entity.
113+
*
114+
* @Route("/new", name="admin_post_new")
115+
* @Security("has_role('ROLE_ADMIN')")
116+
*/
117+
public function newAction()
118+
{
119+
// ...
120+
}
121+
122+
Expression のよる複雑なセキュリティの制限
123+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124+
125+
セキュリティロジックがかなり複雑な場合は、
126+
``@Security`` の内部で `expression`_ を利用できます。
127+
例えば、
128+
``Post`` オブジェクトの ``getAuthorEmail`` メソッドの返り値とメールアドレスが一致したときのみ
129+
コントローラーへのアクセスを許可したい場合は以下のように実装できます。
130+
131+
.. code-block:: php
132+
133+
use AppBundle\Entity\Post;
134+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
135+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
136+
137+
/**
138+
* @Route("/{id}/edit", name="admin_post_edit")
139+
* @Security("user.getEmail() == post.getAuthorEmail()")
140+
*/
141+
public function editAction(Post $post)
142+
{
143+
// ...
144+
}
145+
146+
``Post`` オブジェクトとそれに与えられる ``$post`` という引数を自動的に取得する
147+
ために `PramConverter`_ の利用が必須であることに注意してください。
148+
149+
この方法は有名な欠点を持っています。
150+
アノテーションによる記述は、アプリケーションの他の部分で簡単に再利用できません。
151+
投稿の著者のみが閲覧できるテンプレートのリンクを追加したい場合を想像してください。
152+
Twig の文法を利用して再び記述する必要があることがすぐに思い浮かぶでしょう。
153+
154+
.. code-block:: html+jinja
155+
156+
{% if app.user and app.user.email == post.authorEmail %}
157+
<a href=""> ... </a>
158+
{% endif %}
159+
160+
十分にシンプルなロジックの場合、最も簡単な解決手段は
161+
与えられたユーザがその投稿の著者であるかをチェックする新しい関数を ``Post`` エンティティに追加することです。
162+
163+
.. code-block:: php
164+
165+
// src/AppBundle/Entity/Post.php
166+
// ...
167+
168+
class Post
169+
{
170+
// ...
171+
172+
/**
173+
* Is the given User the author of this Post?
174+
*
175+
* @return bool
176+
*/
177+
public function isAuthor(User $user = null)
178+
{
179+
return $user && $user->getEmail() == $this->getAuthorEmail();
180+
}
181+
}
182+
183+
これで、この関数をテンプレートとセキュリティの記述のどちらでも再利用できます。
184+
185+
.. code-block:: php
186+
187+
use AppBundle\Entity\Post;
188+
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
189+
190+
/**
191+
* @Route("/{id}/edit", name="admin_post_edit")
192+
* @Security("post.isAuthor(user)")
193+
*/
194+
public function editAction(Post $post)
195+
{
196+
// ...
197+
}
198+
199+
.. code-block:: html+jinja
200+
201+
{% if post.isAuthor(app.user) %}
202+
<a href=""> ... </a>
203+
{% endif %}
204+
205+
.. _best-practices-directy-isGranted:
206+
207+
@Security を利用しない権限のチェック
208+
--------------------------------------
209+
210+
これまでの例は、
211+
``post`` という変数にアクセスできる記述を提供してくれる :ref:`ParamConverter <best-practices-paramconverter>` を
212+
利用する場合のみ動作します。
213+
これを利用しない場合やより応用的なユースケースの場合は、PHP で同様のセキュリティチェックができます。
214+
215+
.. code-block:: php
216+
217+
/**
218+
* @Route("/{id}/edit", name="admin_post_edit")
219+
*/
220+
public function editAction($id)
221+
{
222+
$post = $this->getDoctrine()->getRepository('AppBundle:Post')
223+
->find($id);
224+
225+
if (!$post) {
226+
throw $this->createNotFoundException();
227+
}
228+
229+
if (!$post->isAuthor($this->getUser())) {
230+
throw $this->createAccessDeniedException();
231+
}
232+
233+
// ...
234+
}
235+
236+
セキュリティ Voter
237+
---------------
238+
239+
セキュリティロジックが複雑で ``isAuthor()`` のようなメソッドに局所化できない場合、
240+
カスタム Voter を利用することができます。
241+
これらは `ACL's`_ よりもかなり簡単な方法かつほぼ全てのケースに柔軟に対応できます。
242+
243+
まずはじめに、Voter クラスを作成します。以下の例では、これまでと同じ ``getAuthorEmail`` ロジックを
244+
実装した Voter について示します。
245+
246+
.. code-block:: php
247+
248+
namespace AppBundle\Security;
249+
250+
use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
251+
use Symfony\Component\Security\Core\User\UserInterface;
252+
253+
// AbstractVoter class requires Symfony 2.6 or higher version
254+
class PostVoter extends AbstractVoter
255+
{
256+
const CREATE = 'create';
257+
const EDIT = 'edit';
258+
259+
protected function getSupportedAttributes()
260+
{
261+
return array(self::CREATE, self::EDIT);
262+
}
263+
264+
protected function getSupportedClasses()
265+
{
266+
return array('AppBundle\Entity\Post');
267+
}
268+
269+
protected function isGranted($attribute, $post, $user = null)
270+
{
271+
if (!$user instanceof UserInterface) {
272+
return false;
273+
}
274+
275+
if ($attribute === self::CREATE && in_array('ROLE_ADMIN', $user->getRoles(), true)) {
276+
return true;
277+
}
278+
279+
if ($attribute === self::EDIT && $user->getEmail() === $post->getAuthorEmail()) {
280+
return true;
281+
}
282+
283+
return false;
284+
}
285+
}
286+
287+
アプリケーションでセキュリティ Voter を有効にするために新しいサービスを定義します。
288+
289+
.. code-block:: yaml
290+
291+
# app/config/services.yml
292+
services:
293+
# ...
294+
post_voter:
295+
class: AppBundle\Security\PostVoter
296+
public: false
297+
tags:
298+
- { name: security.voter }
299+
300+
ここで ``@Security`` アノテーションに Voter を利用してみます。
301+
302+
.. code-block:: php
303+
304+
/**
305+
* @Route("/{id}/edit", name="admin_post_edit")
306+
* @Security("is_granted('edit', post)")
307+
*/
308+
public function editAction(Post $post)
309+
{
310+
// ...
311+
}
312+
313+
これを直接 ``security.context`` と一緒に使うことも可能です。
314+
また、コントローラーでより簡潔なショートカットを経由することも可能です。
315+
316+
.. code-block:: php
317+
318+
/**
319+
* @Route("/{id}/edit", name="admin_post_edit")
320+
*/
321+
public function editAction($id)
322+
{
323+
$post = // query for the post ...
324+
325+
if (!$this->get('security.context')->isGranted('edit', $post)) {
326+
throw $this->createAccessDeniedException();
327+
}
328+
}
329+
330+
さらに学ぶためには
331+
----------
332+
333+
Symfony のコミュニティによって開発された `FOSUserBundle`_ は Symfony2 における
334+
データベースによるユーザシステムのサポートを追加しました。
335+
これはユーザの登録やパスワードを忘れた時の機能などの共通のタスクも取り扱っています。
336+
337+
`Remember Me feature`_ を有効にすることによってユーザを長期期間ログインさせておくことも可能です。
338+
339+
カスタマーサポートを提供したとき、問題を再現するために異なるユーザでアプリケーションにアクセス
340+
することがたびたび必要になります。
341+
Symfony は `impersonate users`_ の機能を提供しています。
342+
343+
Symfony でサポートしていないユーザのログインメソッドを利用する場合、
344+
`your own user provider`_ と `your own authentication provider`_ で開発することができます。
345+
346+
.. _`Security Cookbook Section`: http://symfony.com/doc/current/cookbook/security/index.html
347+
.. _`security.yml`: http://symfony.com/doc/current/reference/configuration/security.html
348+
.. _`ParamConverter`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
349+
.. _`@Security annotation`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
350+
.. _`security.yml`: http://symfony.com/doc/current/reference/configuration/security.html
351+
.. _`security voter`: http://symfony.com/doc/current/cookbook/security/voters_data_permission.html
352+
.. _`Acces Control List`: http://symfony.com/doc/current/cookbook/security/acl.html
353+
.. _`ACL's`: http://symfony.com/doc/current/cookbook/security/acl.html
354+
.. _`expression`: http://symfony.com/doc/current/components/expression_language/introduction.html
355+
.. _`FOSUserBundle`: https://github.com/FriendsOfSymfony/FOSUserBundle
356+
.. _`Remember Me feature`: http://symfony.com/doc/current/cookbook/security/remember_me.html
357+
.. _`impersonate users`: http://symfony.com/doc/current/cookbook/security/impersonating_user.html
358+
.. _`your own user provider`: http://symfony.com/doc/current/cookbook/security/custom_provider.html
359+
.. _`your own authentication provider`: http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html

0 commit comments

Comments
 (0)