Skip to content

Commit a233a70

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

File tree

1 file changed

+360
-0
lines changed

1 file changed

+360
-0
lines changed

best_practices/security.rst

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

0 commit comments

Comments
 (0)