-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathsecurity.xml
171 lines (148 loc) · 6.23 KB
/
security.xml
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 565e478d69a9d0c217eda773c77ca823423adf21 Maintainer: takagi Status: ready -->
<chapter xml:id="mongo.security" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>セキュリティ</title>
<section>
<title>リクエストインジェクション攻撃</title>
<para>
クエリに <literal>$_GET</literal> (あるいは <literal>$_POST</literal>) パラメータを渡している場合は、
まず最初にそれを文字列にキャストすることを忘れないようにしましょう。
GET リクエストや POST リクエストには連想配列を入れることもでき、
そのまま使うと期待通りのクエリにはなりません。
</para>
<para>
当たり障りのない例を示します。ユーザーの情報を調べるときに
<emphasis>http://www.example.com?username=bob</emphasis>
のようなリクエストを送っているとしましょう。アプリケーション側では
<literal>$collection->find(array("username" => $_GET['username']))</literal>
のような問い合わせをします。
</para>
<para>
ここで、誰かが
<emphasis>http://www.example.com?username[$ne]=foo</emphasis>
のようなリクエストを送ったとします。PHP はこれを自動的に連想配列に変換するので、クエリは
<literal>$collection->find(array("username" => array('$ne' => "foo")))</literal>
のようになります。これは、名前が "foo" ではないユーザーすべて (おそらく全員でしょうね)
の情報を返すことになります。
</para>
<para>
この攻撃を防ぐのはきわめて簡単です。$_GET パラメータや $_POST パラメータが期待通りの型であることを確かめてから
データベースにリクエストを送ればよいのです (この場合は、文字列にキャストすることになります)。
</para>
<para>
この種の攻撃は、ドキュメントを指すすべてのデータベース操作で可能であることに気をつけましょう。
更新や upsert、find した内容の修正、削除などがこれにあたります。
</para>
<para>
<link xlink:href="&url.mongodb.injection;">Phil</link> の指摘に感謝します。
</para>
<para>
<link xlink:href="&url.mongodb.dochub.security;">メインドキュメント</link>
には、MongoDB における SQL インジェクション風の問題に関する詳細な情報があります。
</para>
</section>
<section>
<title>スクリプトインジェクション攻撃</title>
<para>
JavaScript を使う場合、PHP と JavaScript をまたぐ変数の受け渡しは
<classname>MongoCode</classname> の <literal>scope</literal>
フィールドで行いましょう。JavaScript の文字列にしてはいけません。
このような受け渡しが発生するのは、<function>MongoDB::execute</function> や
<literal>$where</literal> 句、MapReduce、group-by、そしてその他
JavaScript をデータベースに渡す場合です。
</para>
<note>
<para>
MapReduce は <classname>MongoCode</classname> の
<literal>scope</literal> フィールドを無視しますが、コマンドのオプション
<literal>scope</literal> をかわりに使うことができます。
</para>
</note>
<para>
たとえば、JavaScript を使ってデータベースログのユーザーにあいさつをするとしましょう。
こんなふうに書くことができます。
</para>
<programlisting role="php">
<![CDATA[
<?php
// これはやっちゃだめ!
$username = $_POST['username'];
$db->execute("print('Hello, $username!');");
?>
]]>
</programlisting>
<para>
しかし、悪意のあるユーザーがこんな JavaScript を渡したとしたらどうなるでしょう?
</para>
<programlisting role="php">
<![CDATA[
<?php
// これはやっちゃだめ!
// $username に "'); db.users.drop(); print('" が入っているとすると…
$db->execute("print('Hello, $username!');");
?>
]]>
</programlisting>
<para>
このとき MongoDB が実行する JavaScript 文字列は
<literal>"print('Hello, '); db.users.drop(); print('!');"</literal>
となります。この手の攻撃を回避するのは簡単で、変数を PHP から JavaScript
に渡すときに <literal>scope</literal> を使います。
</para>
<programlisting role="php">
<![CDATA[
<?php
$scope = array("user" => $username);
$db->execute(new MongoCode("print('Hello, '+user+'!');", $scope));
?>
]]>
</programlisting>
<para>
これは、変数 <literal>user</literal> を JavaScript のスコープに渡します。
もし誰かが悪意のあるコードを仕込んだとしても、MongoDB は何の被害も受けずに単に
<literal>Hello, '); db.dropDatabase(); print('!</literal>
と表示するまでです。
</para>
<para>
<literal>scope</literal> を使えば、悪意のある入力がデータベースで実行されることを防ぐ助けになります。
しかし、コードの中で入力を実行してしまわないように注意が必要です。
たとえば、JavaScript <literal>eval</literal>
関数をユーザーの入力に対して決して使ってはいけません。
</para>
<programlisting role="php">
<![CDATA[
<?php
// これはやっちゃだめ!
// $jsShellInput は "db.users.drop();" です
$scope = array("input" => $jsShellInput);
$db->execute(new MongoCode("eval(input);", $scope));
?>
]]>
</programlisting>
<para>
常に <literal>scope</literal> を使い、
決してユーザーの入力をデータベースのコードとして実行させないようにしましょう。
</para>
</section>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->