-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcsrf.html
130 lines (126 loc) · 5.69 KB
/
csrf.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Ethnamドキュメント</title>
<link href="css/style.css" media="all" rel="stylesheet" />
<link href="css/github.css" media="all" rel="stylesheet" />
</head>
<body>
<p><a href=".">目次</a></p>
<div class="blob instapaper_body">
<article class="markdown-body entry-content">
<h1>クロスサイトリクエストフォージェリの対策コードについて</h1>
<ul>
<li>概要 </li>
<li>準備 </li>
<li>(1) POSTの正当性を保証するためのIDを生成する
<ul>
<li>(余談) </li>
</ul></li>
<li>(2)テンプレートで{csrfid}でHidden値を生成する </li>
<li>(3) Ehna_Util::isCsrfSafe()で、正当性を確認する。
<ul>
<li>(余談) </li>
</ul></li>
</ul>
<p>| 書いた人 | 日付 | 備考 |
| cocoiti | 2006-011-01 | 初版 |
| halt | 2006-011-01 | 具体的な例を提示 |</p>
<h2>クロスサイトリクエストフォージェリの対策コードについて</h2>
<h3>概要</h3>
<p>EthnaはPOSTとGETを区別しないため、クロスサイトリクエストフォージェリ(以下CSRF)については一般的なリンクによる攻撃でもCSRFが成立します。</p>
<p>例として、 認証が必要なDeleteアクションを外部の人間がCSRFを利用して実行する場合を考えてみます。 DeleteアクションはidをPOSTされるとそのidを持つカラムを削除する機能をもっていたとします。だいたい以下のような実装です。</p>
<p>DeleteActionForm</p>
<pre><code>-- 中略 --
'id' => array(
'name' => 'id',
'type' => VAR_TYPE_INT,
'form_type' => FORM_TYPE_TEXT,
'required' => true,
),
'submit' => array(
'name' => 'submit',
'type' => VAR_TYPE_STRING,
'form_type' => FORM_TYPE_SUBMIT,
'required' => true,
),
-- 中略 --</code></pre>
<p>DeleteAction</p>
<pre><code>-- 中略 --
function prepare()
{
if ($this->af->validate() > 0) {
return 'error';
} else {
return null;
}
}
function perform()
{
-- データを削除する処理 --
}
-- 中略 --</code></pre>
<p>このアクションには認証がかかっているため、悪意のある人間がアクセスしても、認証をクリアするためのid,passwordなどを知っていないとアクセスできませんが、すでにログインし、認証済みのユーザに、</p>
<pre><code>http://example.com/?action_delete=true&id=100&submit=aaa</code></pre>
<p>というURLをメールで送りつけるなどして認証済みのユーザにアクセスさせた場合、アクセスさせた相手の認証情報を使ってこちらが意図したidの記事を削除させることができます。</p>
<p>一般的には、それぞれ、なんらかの対策コードを追加していたと思いますが、Ethnaで次のようなヘルパを作成しました。</p>
<h3>準備</h3>
<p>etc/APPID.ini.phpに、Ethna_Plugin_Csrfのどの実装を利用するかを指定します。 デフォルトでは、Sessionが呼び出されます。(現状では、Sessionしか用意されていません)</p>
<h3>(1) POSTの正当性を保証するためのIDを生成する</h3>
<p>まず、入力画面もしくは、APPID_ActionClassのデフォルトの動作のどちらかで、IDを生成します。 難しく聞こえますが、要するにロジックのどこかで</p>
<pre><code>Ethna_Util::setCsrfID();</code></pre>
<p>を実行するだけです。</p>
<p>ここでは仮に、Inputアクションのperform()に記述します。</p>
<pre><code>class Csrf_Action_Input extends Csrf_ActionClass
{
function perform()
{
Ethna_Util::setCsrfID();
return 'Input';
}
}</code></pre>
<p>生成されるIDの実装などは特にプログラマが意識することはありません。</p>
<h4>(余談)</h4>
<p>また、一度実行されれば(実装によりますが、たとえばSessionの場合は)その、Sessionが削除されるまでは同一のIDが保証されます。 Ethna_Util::setCsrfID();を二回実行しても動作に影響はありません。 また、Sessionの実装の場合は、これを実行するとSessionが開始されることも注意してください。</p>
<h3>(2)テンプレートで{csrfid}でHidden値を生成する</h3>
<p>Inputアクションから呼び出されるテンプレートInput.tplのFormの入力画面に{csrfid}を追加します。</p>
<p>例:</p>
<pre><code>{form ethna_action="input_do" method="post"}
{csrfid}
名前: {form_input name="name"}
{form_input name="submit"}
{/form}</code></pre>
<h3>(3) Ehna_Util::isCsrfSafe()で、正当性を確認する。</h3>
<p>formのデータ送信先であるinput_doアクションで、Postの正当性を確認します。</p>
<pre><code>class Csrf_Action_Input_Do extends Csrf_ActionClass
{
function prepare()
{
if(! Ethna_Util::isCsrfSafe()) {
return 'error';
}
if(! $this->af->validate()) {
return 'input';
}
return null;
}
}</code></pre>
<p>これでCSRFの対策コードの完了です。エラー処理などは、サイトのポリシーによって適切に行ってください。</p>
<h4>(余談)</h4>
<p>上記コードをどのタイミングで行うのかということですが、基本的に</p>
<ul>
<li>DBに書き込む</li>
<li>メールを送る</li>
</ul>
<p>など、具体的なアクションを行う所で行うべきだと思います。</p>
<ul>
<li>入力確認画面</li>
</ul>
<p>などは、無くても問題ない場合が多いと思います。</p> </article>
</div>
<div class="site-footer">
@2015 <a href="https://twitter.com/DQNEO">DQNEO</a>
</div>
</body>
</html>