Bug(バグ) #2534
完了管理画面: 招待メール送信からメンバー登録をおこなうと他人のメールアドレスが登録されてしまう場合がある
100%
説明
Overview (現象)¶
管理画面:招待メール送信画面 (/pc_backend.php/member/invite)から複数のメールアドレスに対して招待をおこなうと、全てのデータ同じメンバーIDに登録され、有効なtokenをもつ招待メールが最後の一通のみとなる(携帯メールアドレスを含む場合は最後に記載されていた携帯メールアドレス宛のものになる?)。
同じメンバーIDに情報が登録されることで、以下の情報が同じメンバーのものとして扱われる。
- PCメールアドレスのなかで最も下の行に記載されていたメールアドレス
- 携帯メールアドレス(mobile_address_pre が複数登録される)
このため、最終行が携帯メールアドレスだった場合(もしくは、送信内容に携帯メールアドレスが含まれる場合?)、携帯で受け取ったメールアドレスを pc_frontend から登録すると、登録されるメールアドレスが他人のものになる。
現象再現手順¶
1. 招待メール送信画面を表示 (/pc_backend.php/member/invite)
2. 以下のようにメールアドレスを複数入力する
sakai+test1@tejimaya.com senpai.so903@docomo.ne.jp sakai+test2@tejimaya.com kiw1540mm@docomo.ne.jp
2 の時点で4つのメールアドレスに招待メールが飛ばされるが、有効なtokenをもつ招待メールは kiw1540mm〜 宛のみ。
member_config のデータは以下のようになっている。
mysql> select * from member_config where member_id=22; +-----+-----------+----------------------+------------------------------------+----------------+----------------------------------+---------------------+---------------------+ | id | member_id | name | value | value_datetime | name_value_hash | created_at | updated_at | +-----+-----------+----------------------+------------------------------------+----------------+----------------------------------+---------------------+---------------------+ | 142 | 22 | pc_address_pre | sakai+test2@tejimaya.com | NULL | 97e8f0a409830627773610b4909180b5 | 2011-10-20 15:55:21 | 2011-10-20 15:55:22 | | 143 | 22 | pc_address_token | 5cf2a5b8040e0aac61fce6797c84ee97 | NULL | 696ba1b398296980b5b8f6901e7a90d5 | 2011-10-20 15:55:21 | 2011-10-20 15:55:22 | | 144 | 22 | register_token | 225b6865c323a1931085e4d7184c66710d | NULL | 37c681aa93e35f48f7c9a5b06007dd66 | 2011-10-20 15:55:21 | 2011-10-20 15:55:25 | | 145 | 22 | register_auth_mode | MailAddress | NULL | fba890f9ba38ac0b250c1d2f2fc42afc | 2011-10-20 15:55:22 | 2011-10-20 15:55:22 | | 146 | 22 | is_admin_invited | 1 | NULL | eb60f13757f1516e0031606640744834 | 2011-10-20 15:55:22 | 2011-10-20 15:55:22 | | 147 | 22 | mobile_address_pre | senpai.so903@docomo.ne.jp | NULL | 7c59d17726cd5398a8a00be873b7cd11 | 2011-10-20 15:55:23 | 2011-10-20 15:55:23 | | 148 | 22 | mobile_address_token | 63280c310c45aa09319df583366611ca | NULL | c9d1952bb0a82c9137c1df0e11e446da | 2011-10-20 15:55:23 | 2011-10-20 15:55:23 | | 149 | 22 | mobile_address_pre | kiw1540mm@docomo.ne.jp | NULL | 7bcacac9ecdb4e0c0021941afcd4f0ba | 2011-10-20 15:55:24 | 2011-10-20 15:55:24 | | 150 | 22 | mobile_address_token | 3cf29cc3889867ef3b72e6ef126b0556 | NULL | 0afadaac6b87170b1b8e56470957ae67 | 2011-10-20 15:55:25 | 2011-10-20 15:55:25 | +-----+-----------+----------------------+------------------------------------+----------------+----------------------------------+---------------------+---------------------+
3. kiw1540mm〜 におくられてきたメールをPCに転送し、PCからメンバー登録をおこなう
4. sakai+test2〜 のメールアドレスでメンバー登録が完了し、 sakai+test2〜 宛にメンバー完了通知が届く
メンバー登録完了後の member_config は以下のとおり。
mysql> select * from member_config where member_id=22; +-----+-----------+----------------------+------------------------------------+---------------------+----------------------------------+---------------------+---------------------+ | id | member_id | name | value | value_datetime | name_value_hash | created_at | updated_at | +-----+-----------+----------------------+------------------------------------+---------------------+----------------------------------+---------------------+---------------------+ | 142 | 22 | pc_address | sakai+test2@tejimaya.com | NULL | 5daba3b9e300785c2d7f2b32766a2d27 | 2011-10-20 15:55:21 | 2011-10-20 15:58:41 | | 144 | 22 | register_token | 225b6865c323a1931085e4d7184c66710d | NULL | 37c681aa93e35f48f7c9a5b06007dd66 | 2011-10-20 15:55:21 | 2011-10-20 15:55:25 | | 145 | 22 | register_auth_mode | MailAddress | NULL | fba890f9ba38ac0b250c1d2f2fc42afc | 2011-10-20 15:55:22 | 2011-10-20 15:55:22 | | 146 | 22 | is_admin_invited | 1 | NULL | eb60f13757f1516e0031606640744834 | 2011-10-20 15:55:22 | 2011-10-20 15:55:22 | | 147 | 22 | mobile_address_pre | senpai.so903@docomo.ne.jp | NULL | 7c59d17726cd5398a8a00be873b7cd11 | 2011-10-20 15:55:23 | 2011-10-20 15:55:23 | | 148 | 22 | mobile_address_token | 63280c310c45aa09319df583366611ca | NULL | c9d1952bb0a82c9137c1df0e11e446da | 2011-10-20 15:55:23 | 2011-10-20 15:55:23 | | 149 | 22 | mobile_address_pre | kiw1540mm@docomo.ne.jp | NULL | 7bcacac9ecdb4e0c0021941afcd4f0ba | 2011-10-20 15:55:24 | 2011-10-20 15:55:24 | | 151 | 22 | secret_question | 1 | NULL | 388f9fd417f5cc3e8f0fdf68c16b8b9f | 2011-10-20 15:58:41 | 2011-10-20 15:58:41 | | 152 | 22 | secret_answer | 098f6bcd4621d373cade4e832627b4f6 | NULL | eb308689eafa0f3aaddc10b8960b8d06 | 2011-10-20 15:58:41 | 2011-10-20 15:58:41 | | 153 | 22 | age_public_flag | 3 | NULL | 5a988ab486eb640588b479e1c0155045 | 2011-10-20 15:58:41 | 2011-10-20 15:58:41 | | 154 | 22 | password | 5f4dcc3b5aa765d61d8327deb882cf99 | NULL | 927246e0e2492bb1c4334e89edfa252f | 2011-10-20 15:58:41 | 2011-10-20 15:58:41 | | 155 | 22 | mail_address_hash | 4ivf7soaf6rv | NULL | e435e5b97398ffb458bb6b591bcdf337 | 2011-10-20 15:58:41 | 2011-10-20 15:58:41 | | 156 | 22 | lastLogin | | 2011-10-20 15:58:49 | 83f893f513b36f24c7bbdf4839c518b0 | 2011-10-20 15:58:44 | 2011-10-20 15:58:49 | +-----+-----------+----------------------+------------------------------------+---------------------+----------------------------------+---------------------+---------------------+
確認バージョン¶
OpenPNE 3.6.0
Causes (原因)¶
Way to fix (修正内容)¶
Kiwa Sakai さんが約13年前に更新
- 説明 を更新 (差分)
現在までの確認の限りでは悪意をもったユーザが意図的に操作できる問題ではなさそうですが、念の為セキュリティイシューにさせてもらいました。
Yuya Watanabe さんが約13年前に更新
原因¶
#1816 でのコミット b6471e84 によって追加された以下の部分が正しくない.
具体的には,すべてのMemberが新規登録の場合,$this->validateAddress('pc_address', $value)がtrueになるため一回もcreatePre()が実行されずに現在ある$this->memberの一つを用いてmember_configへの記録が行われる.
また,$this->memberに既存のMemberオブジェクトを取得する処理が行われないため,すでに登録されているメンバのアドレスの前後に記載したアドレスに影響を与える可能性がある.
追記:validateAddress()内で$this->memberを更新する処理があるため,問題ないと考えられる.
apps/pc_backend/modules/member/lib/AdminInviteForm.class.php 76行目,87行目
73 74 foreach ($this->getValue('pc') as $value) 75 { 76 if (!$this->validateAddress('pc_address', $value)) 77 { 78 $this->member = Doctrine::getTable('Member')->createPre(); 79 } 80 $this->saveConfig('pc_address', $value); 81 $this->member->setConfig('register_auth_mode', $authMode); 82 $this->member->setConfig('is_admin_invited', true); 83 } 84 85 foreach ($this->getValue('mobile') as $value) 86 { 87 if (!$this->validateAddress('mobile_address', $value)) 88 { 89 $this->member = Doctrine::getTable('Member')->createPre(); 90 } 91 $this->saveConfig('mobile_address', $value); 92 $this->member->setConfig('register_auth_mode', $authMode); 93 $this->member->setConfig('is_admin_invited', true); 94 } 95
Yuya Watanabe さんが約13年前に更新
修正案¶
diff --git a/apps/pc_backend/modules/member/lib/AdminInviteForm.class.php b/apps/pc_backend/modules/member/lib/AdminInviteForm.class.php index 4eda478..9e69235 100644 --- a/apps/pc_backend/modules/member/lib/AdminInviteForm.class.php +++ b/apps/pc_backend/modules/member/lib/AdminInviteForm.class.php @@ -71,26 +71,33 @@ class AdminInviteForm extends InviteForm $authMode = $authModes[$this->getValue('auth_mode')]; $this->setOption('authMode', $authMode); + $memberConfigTable = Doctrine::getTable('MemberConfig'); foreach ($this->getValue('pc') as $value) { - if (!$this->validateAddress('pc_address', $value)) + if ($this->validateAddress('pc_address', $value)) { - $this->member = Doctrine::getTable('Member')->createPre(); + if (!$memberConfigTable->retrieveByNameAndValue('pc_address_pre', $value)) + { + $this->member = Doctrine::getTable('Member')->createPre(); + } + $this->saveConfig('pc_address', $value); + $this->member->setConfig('register_auth_mode', $authMode); + $this->member->setConfig('is_admin_invited', true); } - $this->saveConfig('pc_address', $value); - $this->member->setConfig('register_auth_mode', $authMode); - $this->member->setConfig('is_admin_invited', true); } foreach ($this->getValue('mobile') as $value) { - if (!$this->validateAddress('mobile_address', $value)) + if ($this->validateAddress('mobile_address', $value)) { - $this->member = Doctrine::getTable('Member')->createPre(); + if (!$memberConfigTable->retrieveByNameAndValue('mobile_address_pre', $value)) + { + $this->member = Doctrine::getTable('Member')->createPre(); + } + $this->saveConfig('mobile_address', $value); + $this->member->setConfig('register_auth_mode', $authMode); + $this->member->setConfig('is_admin_invited', true); } - $this->saveConfig('mobile_address', $value); - $this->member->setConfig('register_auth_mode', $authMode); - $this->member->setConfig('is_admin_invited', true); } return true;
Kousuke Ebihara さんが約13年前に更新
既にこの現象に遭遇している SNS において、画面からの操作によって妥当な状態にデータを変更する手段は存在しません。そのため、以下の SQL を実行することをアドバイスすることになると思います。
# 削除対象となる未登録メンバーを確認します (2020-01-01 00:00:00 は OpenPNE 3.6 にアップデートしてから、管理画面からの招待をおこなうまでの任意の日時に置き換えてください) SELECT * FROM member WHERE id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1" AND created_at > "2020-01-01 00:00:00") AND is_active = 0; # 確認した未登録メンバーを削除します (2020-01-01 00:00:00 は OpenPNE 3.6 にアップデートしてから、管理画面からの招待をおこなうまでの任意の日時に置き換えてください) DELETE FROM member WHERE id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1" AND created_at > "2020-01-01 00:00:00") AND is_active = 0;
※登録済みメンバーの復旧方法は追って提示します
Kousuke Ebihara さんが約13年前に更新
# 削除対象となるメールアドレスおよび登録用トークンを確認します (2020-01-01 00:00:00 は OpenPNE 3.6 にアップデートしてから、管理画面からの招待をおこなうまでの任意の日時に置き換えてください) SELECT * FROM member_config WHERE name IN ("mobile_address_pre", "pc_address_pre", "mobile_address_token", "pc_address_token") AND member_id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1" AND created_at > "2020-01-01 00:00:00"); # 確認したメールアドレスおよび登録用トークンを削除します (2020-01-01 00:00:00 は OpenPNE 3.6 にアップデートしてから、管理画面からの招待をおこなうまでの任意の日時に置き換えてください) DELETE FROM member_config WHERE name IN ("mobile_address_pre", "pc_address_pre", "mobile_address_token", "pc_address_token") AND member_id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1" AND created_at > "2020-01-01 00:00:00"); この操作をおこなうと、指定した日時以降に設定変更から「携帯メールアドレス登録」もしくは「PCメールアドレス登録」をおこなおうとしたメンバーのうち、管理者からの招待状を経由して登録した者による手続きがすべて無効になります。そのため、実施後は「携帯メールアドレス登録」もしくは「PCメールアドレス登録」をやり直すように利用者に対して告知をおこなってください。
Kousuke Ebihara さんが約13年前に更新
この問題により生じうるリスクを以下にまとめます。
- このチケットで説明されているような「このため、最終行が携帯メールアドレスだった場合(もしくは、送信内容に携帯メールアドレスが含まれる場合?)、携帯で受け取ったメールアドレスを pc_frontend から登録すると、登録されるメールアドレスが他人のものになる。」という手順を踏まれてしまうことで、他人のメールアドレスによる登録がおこなわれてしまう
- 登録に使われなかったメールアドレスを本当に所有するユーザが、そのメールアドレスを使用して新規登録できなくなる
ここに示した以外のリスクは、確認した限りでは特に見つかりませんでした。
Kiwa Sakai さんが約13年前に更新
note-5 のSQLを(created_at の条件を削除して)実行してみましたが、エラーが発生してデータの削除に失敗しました。
DELETE文実行結果 (エラーが発生)¶
mysql> DELETE FROM member_config WHERE name IN ("mobile_address_pre", "pc_address_pre", "mobile_address_token", "pc_address_token") AND member_id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1"); ERROR 1093 (HY000): You can't specify target table 'member_config' for update in FROM clause
SELECT文実行結果 (問題ない)¶
mysql> SELECT * FROM member_config WHERE name IN ("mobile_address_pre", "pc_address_pre", "mobile_address_token", "pc_address_token") AND member_id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1"); +----+-----------+----------------------+----------------------------------+----------------+----------------------------------+---------------------+---------------------+ | id | member_id | name | value | value_datetime | name_value_hash | created_at | updated_at | +----+-----------+----------------------+----------------------------------+----------------+----------------------------------+---------------------+---------------------+ | 27 | 5 | mobile_address_pre | senpai.so903@docomo.ne.jp | NULL | 7c59d17726cd5398a8a00be873b7cd11 | 2011-10-21 16:26:16 | 2011-10-21 16:26:16 | | 28 | 5 | mobile_address_token | c3a9264f890aa76aef1c9437329912b5 | NULL | 2bdf6295e3b87b7add018385a655ab6b | 2011-10-21 16:26:16 | 2011-10-21 16:39:32 | | 29 | 5 | mobile_address_pre | kiw1540mm@docomo.ne.jp | NULL | 7bcacac9ecdb4e0c0021941afcd4f0ba | 2011-10-21 16:26:18 | 2011-10-21 16:26:18 | +----+-----------+----------------------+----------------------------------+----------------+----------------------------------+---------------------+---------------------+ 3 rows in set (0.00 sec)
Minoru Takai さんが約13年前に更新
note-7 についてですが、
mysql> DELETE FROM member_config WHERE name IN ("mobile_address_pre", "pc_address_pre", "mobile_address_token", "pc_address_token") AND member_id IN (SELECT member_id FROM member_config WHERE name = "is_admin_invited" AND value = "1"); ERROR 1093 (HY000): You can't specify target table 'member_config' for update in FROM clause
このエラーは「サブクエリ内の不正使用されたテーブル」の項に示されています。 http://dev.mysql.com/doc/refman/5.1/ja/subquery-errors.html
また、このエラーの概要と回避策については http://www.mysqlfaqs.net/mysql-faqs/Errors/1093-You-can-not-specify-target-table-comments-for-update-in-FROM-clause で次のように示されています。
「 UPDATE や DELETE 文では、対象とするテーブルと同一のテーブルをサブクエリー内で同時に参照することは MySQL ではできないので、そのようなことをしたい場合は、サブクエリーの中でもう一つサブクエリーをラップして temporary table として扱われるようにします」
つまり、 note-7 で示されている DELETE 文は、次のように書き換えることで実行できます。
DELETE FROM member_config WHERE name IN ("mobile_address_pre", "pc_address_pre", "mobile_address_token", "pc_address_token") AND member_id IN (SELECT member_id FROM (SELECT * FROM member_config WHERE name = "is_admin_invited" AND value = "1") AS tmp_member_config);
Kiwa Sakai さんが約13年前に更新
note-3 の修正ですが、軽く基本的な動作を確認した限りでは問題なさそうでした。正式の動作テストの参考になればと思います。
確認内容¶
確認バージョン: OpenPNE 3.6RC2
- PCメールアドレス・携帯メールアドレスが混在する招待
- PCメールアドレス・携帯メールアドレスで別々のメンバーを登録することができる
- 携帯メールアドレスの招待URLをPCでひらく
- 「この登録用URLは携帯電話専用です。」エラーメッセージが表示される
- PCメールアドレスの招待URLを携帯でひらく
- 「この登録用URLはPC専用です。」エラーメッセージが表示される
- 招待メールアドレスのなかに既に登録されているメールアドレスが含まれる
- エラーにならず、登録済みのメールアドレスが無視される
- 招待メールアドレスのリストのなかに pre に登録されているメールアドレスが含まれる
- pre に登録されているメールアドレスも無視される
- 招待メールアドレスのリストのなかに空行が含まれる
- エラーにならず、全てのメールアドレスあてにメールがおくられる
- 招待メールアドレスのなかにメールアドレスではない文字列が含まれる
- エラーにはならず、全ての(正しい)メールアドレス宛にメールが送られる
- 400メールアドレスを一気に入力し、招待メールを送信する
- 30秒程度でタイムアウトになり、60件程度までしかメールを送れない
(具体的な入力値については記録していませんでした)
Kousuke Ebihara さんが約13年前に更新
- 優先度 を Normal(通常) から Urgent(急いで) に変更
- 3.6 で発生するか を Yes (はい) にセット
- 3.4 で発生するか を No (いいえ) にセット
Yuya Watanabe さんがほぼ13年前に更新
- ステータス を New(新規) から Accepted(着手) に変更
- 担当者 を Yuya Watanabe にセット
note-3の修正内容を適用します.
Yuya Watanabe さんがほぼ13年前に更新
- ステータス を Accepted(着手) から Pending Review(レビュー待ち) に変更
- 進捗率 を 0 から 50 に変更
更新履歴 739ac9b0dd4f248e44d996490f66a4cc0af43b7f で適用されました。
Kousuke Ebihara さんがほぼ13年前に更新
- ステータス を Pending Review(レビュー待ち) から Pending Testing(テスト待ち) に変更
- 進捗率 を 50 から 70 に変更
Youichi Kimura さんがほぼ13年前に更新
- ステータス を Pending Testing(テスト待ち) から Fixed(完了) に変更
- 進捗率 を 70 から 100 に変更
テスト完了しました。