Skip to content

Commit a50b870

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

File tree

1 file changed

+363
-0
lines changed

1 file changed

+363
-0
lines changed

best_practices/security.rst

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

0 commit comments

Comments
 (0)