ハトネコエ Web がくしゅうちょう

プログラミングやサーバー・Web制作、チームマネジメントなど得た技術のまとめ

プログラマのための数学LT会 2! 開催しました

プログラマのための数学LT会 2!

ふたたび主催やらせていただきました!

プログラマのための数学LT会 2!』 です。
https://techplay.jp/event/624044

場所は dots. あらため TECH PLAY さんで開催させていただきました。

2回目ですが、1回目開催の時は開催の疲れから
ブログを書いている余裕がなくて書いていませんでしたので、この記事では
1回目開催に至った経緯なども書いていきます。

f:id:nekonenene:20170723022409j:plain

1. まずは今回の反省から

たくさんの人から「タイムキープちゃんとして!」って怒られました。ごめんなさい。
前回、全員が15分で発表を終えるという奇跡的な進行を見せていたので
「まあ、なんとかなるだろう」と甘く思っていたところはあります。

胃がキリリとなるくらい反省したので、
次回はちゃんとカウントダウンを見せるためのタブレットを持ってきます。

あと、15分は短いですね!
皆さんが今回くらいの資料作ってくださるなら、持ち時間はもうちょっと欲しい!
次回は一人の持ち時間20分以上になる予定です。

2. なんでこのイベントを始めたか

そこそこ聞かれるのでまとめておきます。

もともとは、Yahoo!の佐野さんがやっていた プログラマのための数学勉強会 というイベントがありまして、
「これはおもしろいイベントだ」と、私もそこでLT枠で参加させていただいていたんですよね。

ただ、2016年3月の第6回以降、佐野さんが大学院に入ってしまって、なかなか忙しくて、
当初は半年後に開催する予定(と言っていた気がする)だった数学勉強会が開催されず、
「あ~~~発表したいのに無いのかな~~~」と思っていて、
「よし、じゃあ自分がヒマ人だしやるか!」という気持ちになってきました。

誰もやらないなら自分がやるべき!という信条で生きてるので、やるか! と。

とはいえ、何もわからないところから始めるのは不安しかなかったので、
12月に佐野さんに連絡して、2月にお話を伺う機会をいただきました。
それでその後、TECH PLAY(当時はdots.)の担当さんといろいろFacebook Messenger上でやり取りし、開催にこぎつけました。

それが2017年3月におこなわれた1回目のイベントになりました。
で、そのときに「次回は3ヵ月後くらいに」と言ってしまったので、(正直負担もあるので開催に踏み切る決心が大変でしたが)今回の2回目になりました。

2回目開催を決心したときは、「これで最後にしよう」と90%くらい心に決めていたのですが、
いい登壇者の方々がどんどん集まってくれて、「あ、これは3回目もやろう」と急に気持ちが変わりました。
本当に参加者の集まりが心の支えです。

3. 数学は得意なの?

ってことも聞かれるのでついでに書いておきます。

お恥ずかしいことに、大学数学まったくわかりません!

とはいえ、プログラマのための数学LT会に参加されるプログラマの皆さんもほとんどそうなので、
きっと問題ないかと最近は思ってます。

中学高校の頃の数学は得意でしたが、特別好きでなくて、それよりも小学校算数が好きで、
「数学より算数が好き」と中学生当時はよく言ってましたし、小学校算数が一番おもしろいという考えはいまだに変わってないです。

37 × 3 = 111
になるってことは
37 × 27 = 999
ってことで、それすごくない?! とか思ってます。

しかも
37 + 27 = 64
なんですよ?! 2の6乗ですよ!

さらにさっき気付いたんですけど、
37 ÷ 27 = 1.370370370370……
なんと 37 が何度も続くのです!

37と27の組み合わせなんて、見た目は気の難しい頑固者同士みたいな組み合わせなのに、
二人の生み出すパフォーマンスがあまりに華麗すぎてため息が出てきますよね。

そういうのが好きなので、数学が好きというよりは、数字と平面図形に魅力を感じているのだと思います。
行列の計算とかは勉強ととらえてる節があるので、
今回の数学LT会のように「行列はこんなことに使える」をもっと聞いていると考えも変わってくるかもしれません。

4. 今回のイベントについて

だいぶ違う話が長くなりましたが、
プログラマのための数学LT会 2!』 の感想を。

私のはぼんやりした感想ですので、以下の記事のほうがよくまとまっています。

ブログまとめ枠として参加くださいました「まえすとろ」さんの記事
http://lyricalmaestrojp.hatenablog.com/entry/2017/07/20/012502

Togetterのツイートまとめ
https://togetter.com/li/1131615

LT 1 : プログラマのためのトポロジー入門 〜 山手線は丸いのか? (佐野 岳人)

「到着が19時よりちょっと遅れるかも」と連絡来たときは「お気をつけてー」と思うも、
「いや、佐野さんトップバッターじゃん!!」と気付いて慌てました(笑)

結局19時より数分前に到着してよかったです。

www.slideshare.net

けっこうわかりやすいトポロジーの発表でした。
おもしろくて、のめりこんで聞いてたのはよかったんですが、
「時間大丈夫ですか?」と佐野さんに聞かれたときにはすでに15分経過してて「あっ」って思いました。

開会式での会場の反応悪くてけっこう落ち込んでた時間だったので、時間ちゃんと見てなく……。

せっかくプログラム作ってきてくださったのに、デモをおこなう時間がなくて申し訳ない気持ちでした。
でも67ページあるスライドは15分じゃ終わらないよ!佐野さん!(笑)

LT 2 : 計算するということ (おおとや)

前回のアンケートで「難しすぎる」という感想をたくさんいただいてしまったので、
「次回はわかりやすいものを作ってきます」と意気込んでたおおとやさんの発表でした。

前回のように数学に偏らず、プログラミングも関連する話になっていて
会のテーマにも合っていて、いい発表だったなぁ、と私は思いました。

チューリングマシーンは、チューリングマシーンが無限ループにおちいってしまうプログラムをあらかじめ計算できないのだなあと。

speakerdeck.com

こちら側の裏話として、受付に抜けがあったのか、
出欠管理システム上では、おおとやさんがまだ会場にいないことになっていたので、
佐野さんの発表中、「え! 次の発表者まだ来てない!! 次の人どうしよう…」とすごくあせってました…、
で、よく会場を見渡してみるとおおとやさんがいたので安心しました。

今考えると、おおとやさんだからよかったけど、
私との面識ない発表者さんだったら、「よかった、いる…」とならないので、よりいっそうパニくってたと思います。

LT 3 : 四則演算で描くドット絵 正N角形 (荒木義明)

「小学校算数だけで円周率や三角関数が出せる! かんたん!」みたいな調子で話すも、
それを求めるためにマクローリン展開など出てきて、
「たしかに四則演算(足し算引き算かけ算わり算)だけで出せるけど、それに至る原理が小学生にわからないw」
というツッコミオーラが会場内にあふれていて、
荒木さんの「ね! 小学生にもかんたん!」という調子に会場が爆笑に包まれていました。

でも、娘さんがフィボナッチ数列をソラで言えるようになっているそうなので、案外ほんとうに簡単の可能性も・・・

LT 4 : ゆるふわ情報幾何学 (YE)

最初の導入あたりはよかったかと思うんですが、話の飛躍が多くて、
今まで話していた内容とどうつながっているのかわからないような話の展開になることが多く、
だいぶわかりづらい発表になってしまっていたかなと思います。

また、「これは高校数学の範囲内じゃないので省きます」とやると、ただの穴あきで話が進んでしまうので、
わかりづらくても概念だけでも触れておかないと、結局その後の話が理解できなくなって
誰にもわからない発表になってしまいますので、ある程度は説明を入れると良いと思います。

『高校数学までの知識でもわかる発表内容になっていますとありがたいです』とイベントページにはありますが、
決して高校数学外のことを説明しないでと言っているわけではないですので、
ある程度わかりやすく噛みくだいていただけますと幸いです。

「情報幾何学」というものが何か、をまず知らない人が多いので、そこのさわりを触れて、
それが機械学習とどう関連してくのか概念的なところにフォーカスを置いて語ると、参加層の反応がよかったのではと思います。
(「へぇ~、なるほど、情報幾何を学んでみるか」という気持ちになった人が出たと思います)
テーマがよかっただけにもったいないな、ととても思っています。

LT 5 : 有理ホモトピー論とコンピュータ (若月駿)

難しい発表になるだろうなーとテーマから推測していましたが難しかったです(笑)

内容忘れてるところ多いので、スライドが上がってきたら感想追記しようかなと思ったり…

LT 6 : プラレールでつくる論理回路 (Akama Hitoshi)

Developer Summit 2017 でお会いして、
そのときにプラレール論理回路の実物を見て感動して「ぜひ発表を!」とお願いし、
そして今回でその夢が叶いました。とても満足です……。

speakerdeck.com

発表も上手くて、参加者からの皆さんからの反応もとても良くて、ほんとう登壇してくださってよかったです。
次回は オープンソースカンファレンス2017秋 で実物を見られるそうですよ!

最近はマルチスレッドのプラレール回路を作ろうという構想があるものの、
お金と組み立ての時間が厳しいとのこと……。クラウドファンディングやってほしいです……w

LT 7 : 行列の固有値固有ベクトル (根上春)

www.slideshare.net

とてもわかりやすいスライドを作ってくださいました。

まず行列の固有値固有ベクトルの求め方を話したあとに、
それがプログラマの現場でいかに役立つかという丁寧な説明でした。

残念なことに、前半の、求め方について解説する部分でけっこう時間を使ってしまったので、
後半の一番のおもしろい部分であるプログラミングと行列との関わりについて
あまり時間を使えなくなってしまったのが残念でした。

あと、行列を扱う発表は今回たくさんあったので、
根上さんの発表を1個目に持ってくればよかった~! ってけっこう後悔してました。

いやぁ、いいスライドでしたね……。
プログラマのための行列」とか、そんな感じの本を出してほしいですね。

LT 8 : そろそろ数式お絵描きの話でもまとめておくか (鯵坂もっちょ)

https://www.desmos.com/calculator/vypskkl2vd

参加した人が難しい印象を数学に残したまま帰ってほしくなかったので、
このイベント最後の発表は、できるだけ誰でもわかるようなもの。というのは決めていました。

そういうわけで、エンターテイナーもっちょさんの発表なら間違いない!
とトリに入れさせていただきました。
結果、大正解で、会場の皆さんが楽しんでくださり、とても嬉しかったです。

もっちょさんがTwitterに数式お絵かきを上げているのを何度も見ることはあっても、
どういう手順で作っているのか見ることはなかったので、
「なるほど、最初に描きたい絵を用意して、そこに合わせて図形を用意するのか!」っておもしろかったですし、
「desmosは数学わかってる人が使うもの」みたいな先入観があったので、
全然そんなことないじゃん、気軽に使っていいんじゃん、って知ることができました。華のある発表でした。

5. 今までのアンケート結果

最後に、登壇者へのフィードバックになればと、みなさまからお答えいただいておりますアンケートの集計結果を一部公開します。
この集計作業、 1.5 ~ 2.0 時間くらいかかっていて、けっこう負担かかるので、
次回はアンケート用紙の代わりに、アンケートフォームへのQRコード短縮URLが書かれた紙を配ろうかなと考え中です。

継続的にやっていくためには、負担をできるだけ少なくできると次回開催への精神的抵抗が減るかなと…。
会場押さえたらあとは当日の会場設営・撤収だけで済むのが理想だなと……。

プログラマのための数学LT会(第1回)

f:id:nekonenene:20170723051231p:plain

f:id:nekonenene:20170723051241p:plain

f:id:nekonenene:20170723051248p:plain

f:id:nekonenene:20170723051253p:plain

f:id:nekonenene:20170723051258p:plain

f:id:nekonenene:20170723051303p:plain

f:id:nekonenene:20170723051310p:plain

f:id:nekonenene:20170723051314p:plain

プログラマのための数学LT会 2!

f:id:nekonenene:20170723051805p:plain

f:id:nekonenene:20170723051812p:plain

f:id:nekonenene:20170723051821p:plain

f:id:nekonenene:20170723051828p:plain

f:id:nekonenene:20170723051833p:plain

f:id:nekonenene:20170723051838p:plain

f:id:nekonenene:20170723051843p:plain

f:id:nekonenene:20170723051848p:plain

参加者の方々はこれを見てもらうとわかると思うんですが、
「むずかしい」と思った発表はみんな難しいと思ってます。
一人だけが出来ないわけではないので、安心してください。落ち込まないでください。

そして、わからないことは適宜質問していいと思います。
今回の場合ですと、おおとやさんの「停止性問題」のところとか、
説明されるとわかるけど、そのまま先に進まれると先のところも同時にわからなくなる、みたいなものでしたので、
「そこもうちょっと説明を」と思ったら気兼ねなく聞いてみていいと思います。

とはいえ、今回の15分という発表時間ですと、
割り込んで質問を入れたら全然15分じゃ足りなくなっちゃいますから、
発表の持ち時間は次回はもっと長くしますね!

登壇者の方々は、「ちょうどよい」が50%を下回っていかないよう、
うっかり専門用語の説明を省いていないかなど、
参加者層に数学専門家でなくプログラマが多いことに気を付けてスライドを作るとわかりやすくなっていくかと思います。

以上、主催者として振り返る『プログラマのための数学LT会 2!』の感想でした。
まだまだ主催経験少なく不慣れですが、次回をよりよいものにできるようがんばりますので、
今後ともみなさまどうぞよろしくお願い致します。

Ansibleで、サーバー上の特定ディレクトリにあるファイル名一覧を取得する

個人のサーバーでgit運用したくて、Gitbucket を立ててるんです。
それで、この前 Gitbucket の更新をするときにプラグインファイルも更新をかけたのですが、
困ったことに、プラグインをダウンロードするだけのAnsibleタスクだと
古いバージョンのプラグインファイルもディレクトリに残ってしまってバグるんです。

なので、古いプラグインファイルを削除するためにどうしようかと考えて、
ダウンロードするプラグインファイル名一覧と
現在サーバーにあるプラグインファイル名一覧を比較して、それが異なる場合には、
ダウンロード前にサーバー上のプラグインディレクトリを一度削除することにしました。

やり方が少しややこしいのでここに書き残しておきます。
(Ansibleで配列を扱うのは苦労が多いので、AnsibleでがんばるよりはFabricなりCapistranoなりでデプロイを別におこなうのが本当は健全)

1. もともとのタスク構成

こうなってました。

- name: create plugins directory
  become: true
  become_user: "{{ main_user_name }}"
  become_method: sudo
  file:
    path: "{{ gitbucket_plugins_dir }}"
    state: directory

- name: download plugins
  become: true
  become_user: "{{ main_user_name }}"
  become_method: sudo
  get_url:
    url: "{{ item.url }}"
    dest: "{{ gitbucket_plugins_dir }}"
    mode: 0755
  with_items: "{{ gitbucket_plugins }}"
  notify: restart gitbucket

変数 gitbucket_plugins は以下のとおりです。

gitbucket_plugins:
  - name: emoji
    url: https://github.com/gitbucket/gitbucket-emoji-plugin/releases/download/4.4.0/gitbucket-emoji-plugin_2.12-4.4.0.jar
  - name: gist
    url: https://github.com/gitbucket/gitbucket-gist-plugin/releases/download/4.9.0/gitbucket-gist-plugin_2.12-4.9.0.jar

そしてサーバー上には path/to/plugins/ ディレクトリに以下のファイルが入っているとします。

gitbucket-emoji-plugin_2.12-4.4.0.jar
gitbucket-gist-plugin_2.12-4.8.0.jar

このままタスクを実行すると、path/to/plugins/ ディレクトリには

  • gitbucket-emoji-plugin_2.12-4.4.0.jar
  • gitbucket-gist-plugin_2.12-4.8.0.jar
  • gitbucket-gist-plugin_2.12-4.9.0.jar

が存在してしまい、バージョン違いのプラグインが同居して挙動がおかしくなってしまう。そういうわけです。

2. map で解決

そういうわけで、create plugins directory の前に以下のようなタスクを定義することで解決させました。

- name: check current plugins
  become: true
  become_user: root
  find:
    path: "{{ gitbucket_plugins_dir }}"
  register: current_plugins

- set_fact:
    current_plugins_list: >
      {{ current_plugins.files | map(attribute='path') | map('basename') | list | sort }}
    install_plugins_list: >
      {{ gitbucket_plugins | map(attribute='url') | map('basename') | list | sort }}

- set_fact:
    is_gitbucket_plugins_updated: >
      {{ current_plugins_list != install_plugins_list }}

- name: remove plugins directory (when plugins updated)
  become: true
  become_user: "{{ main_user_name }}"
  become_method: sudo
  file:
    path: "{{ gitbucket_plugins_dir }}"
    state: absent
  when: is_gitbucket_plugins_updated

強引な力技ですね・・・(笑)
では、内容を説明していきます。

まず check current plugins にて find を用い、その結果を変数 current_plugins に渡します。

current_plugins.files は、サーバー上のプラグインディレクトリにあるファイルすべての stat を配列で持ちます。

[
  {
    'path': 'path/to/plugins/gitbucket-emoji-plugin_2.12-4.4.0.jar',
    'mode': '0755',
    'size': ...後略
  },
  {
    'path': 'path/to/plugins/gitbucket-gist-plugin_2.12-4.8.0.jar',
    'mode': ...後略
  }
] 

欲しいのはファイル名だけですから、配列の各要素に対してキー名を指定してそこだけ取り出します。
それが map(attribute=‘path’) の部分です。

この Filter をかけることで、配列は以下のようになります。

[
  'path/to/plugins/gitbucket-emoji-plugin_2.12-4.4.0.jar',
  'path/to/plugins/gitbucket-gist-plugin_2.12-4.8.0.jar'
] 

そしてこの path からファイル名の部分だけ取り出すため、
Ansible側で用意されている basename Filter を使います。

map と組み合わせることにより、各要素に対して basename Filter をかけることができ、配列は以下のようになります。

[
  'gitbucket-emoji-plugin_2.12-4.4.0.jar',
  'gitbucket-gist-plugin_2.12-4.8.0.jar'
] 

そしてその後に list Filter をかけます。
さっきまで『配列は以下のようになります』と書いていましたが、実際には map Filter が返すのはmapオブジェクトなので、
list Filter をかけなければ配列にはなりません。

最後に、sort による辞書順の並び替えをしておいて、
このあとの配列の比較に備えます。
この配列を変数 current_plugins_list として保存します。

ダウンロードする予定のプラグイン一覧にも似たような処理をかけて
変数 install_plugins_list に配列を保存します。

そしてこの2つの変数の値が異なるときは
変数 is_gitbucket_plugins_updated は True となり、
サーバー上のプラグインディレクトリの削除がおこなわれる。という仕組みです。

3. 感想

だいぶ無理矢理やってて、魔術じみてますね。
Ansibleで配列使うのはしんどいですが、こういうことができるんだなーと思って書きました。

もう少しがんばれば、プラグインフォルダーを削除するのでなく、
不要になったプラグインファイルだけを削除する、というふうに書けそうな気がしますが、
中途半端なところで妥協しています。

個人サーバーなので複雑なことしたくなくて、アプリケーションの展開までAnsibleにやらせてますが、
結果Ansibleのレシピが複雑になってるので、ちゃんとデプロイツール使ったほうがいいなという気がしてくるこの頃です……。

ヤバイサイトのセキュリティはどれだけヤバイのか検証してみた

1. 前置き

先日、このツイートがエンジニア界隈でちょっとだけ話題になりました。

f:id:nekonenene:20170525191036p:plain

https://twitter.com/ymotongpoo/status/866929418073120769

事の発端は、このツイートにあります。

f:id:nekonenene:20170525191441p:plain

https://twitter.com/e_Traning_html5/status/866677588315447297


WebRTCと言えば、ブラウザを介してリアルタイムボイスチャットをするのに用いられる技術、という認識が一般的ですが、
ポケモンGOに使われている技術』という「ん?」な説明をしており、
その一方でこの人はホームページでHTML5, WebRTCに関する教材販売をしていて、
しかしそのサイトのデザインはとうていサイト作りを教える人のものとは思えない物。

というなかなか強烈なキャラクターを見せてくれました。

f:id:nekonenene:20170525192320p:plain

ttp://yours-company.jp


f:id:nekonenene:20170525192447p:plain

https://twitter.com/e_Traning_html5/status/867038207946272768

私の知ってるHTML5と違う・・・。

さて、このようなサイトで気になってくるのがセキュリティです。
…というのも、このようなツイートを見たからです。

f:id:nekonenene:20170526072108p:plain

https://twitter.com/mpyw/status/866962107606089728

このスクショ1枚だけだったので、おそらくHTTPSでなくHTTPで送信している問題を上げているのでしょう。
とはいえ、そんなサイトは現在まだまだあります。

このサイトであれば、他のセキュリティ的な問題があるかもしれない、
と、セキュリティ素人ながら気になって眺めてみました。

2. パスワードの認識されないログイン画面

f:id:nekonenene:20170526072921p:plain

このような購入画面を経て、

f:id:nekonenene:20170526072900p:plain

ログイン画面に行き着きます。

ここでなんとなくメールアドレスに「 a@a.com 」と書いて
パスワードに「aaaa」と書くと通ったので、「たまたま合ってしまった?」と思いました。
ところが、パスワードを「a」としてもやはり通ってしまいます。

f:id:nekonenene:20170526073406p:plain

これは妙です。どういった判定がなされているのか見てみました。

3. コードの中身は?

HTMLにJavaScriptがそのまま貼られているので、コードを追うのに苦労はしません。

function password_cheack(num){
    var err = 0;
    if(num == 0){
        var str = $('#password').val();
        if(str == ""){
            alert("パスワードを入力してください。");
            $('#password').focus(); //フォーカスを合わせる
            return -1;
        }
        return 0;
    }else if(num == 1){
        var str = $('#password').val();
        var str2 = $('#password2').val();
        if(str2 != str){
            err = -1;
            alert("パスワードが違います。");
            $('#password').focus(); 
            $('#password').select(); //入力された文字列を選択状態にする  
        }
        return err;
    }
};

パスワードチェックはこの部分で、
引数 num = 0 のときは入力フォームである #password の値が空白でないか調べ、空白であればアラートを表示し-1。空白でなければ0を返します。

引数 num = 1 であれば、入力フォームである #password と、hiddenフォームである #password2 の値を比較し、一致していなければアラートを表示し-1、一致していれば0を返します。

ということは、パスワードが一致していない場合でも、hiddenフォームを見れば正しいパスワードを見られるわけで、
その時点でこのパスワードチェックは意味をなしていないわけですが、それは置いておくとして、呼び出し側を見てみましょう。

$('#login').click(function(){
    var err = mail_cheack();
    if(err == -1){
        return -1;
    }
    var err2 = password_cheack(0);
    if(err2 == -1){
        return -1;
    }
    check_database(1);
});

password_cheack(0)

そう、必ず引数は 0 を渡していたのです。
これでは、パスワード欄が入力されているかのチェックしかなされず、たとえパスワードが合っていなくとも、ログインが完了してしまう。そういう仕組みなのでした。

4. 漏れる個人情報

前章にてhiddenフォームである #password2 に正しいパスワードが代入されると書きましたが、
では、どのようにパスワードが代入されているのかを見てみましょう。

function check_database(num){
    var key;
    if(num == 0){
        key = $('#number').val();
    }else if(num == 1){
        key = $('#mail_address').val();
        alert(key);
    }else if(num == 2){
        key = $('#password').val();
    }
    var url = 'http://yours-company.jp/School_Site/account/PHP/database_search.php';
    //var url = 'http://yours-company.jp/School_Site/account/PHP/post.php';
                
    $.ajax( {
        url: url,
        dataType: 'html',
        data: {
            search_no: num,
            search_key: key
        },
        success: function( data ) {
            var datas = data.split(',', 7);
            var err_flag = datas[0];
            var search_type = datas[1];
            var search_key = datas[2];
            var number = datas[3];
            var password = datas[4];
            var mail = datas[5];
            var name = datas[6];
                            
            if(err_flag == 0){
                // パスワードのチェック
                $('#paypal').attr('disabled',false);
                $('#password2').val(password);
                $('#mail_address2').val(mail);
                $('#name').val(name);
                $('#userID').val(number);
                var html = "";
                html = "<p>" + name + "様</br />ご購入頂きありがとうございます。</p>";
                html += "<p>お支払い手続き終了後に" + mail + "のアドレスにご確認メールを致します。ご確認の手続き終了後のご送付になります。</p>"
                $("#kakunin").append(html);
                $("#kakunin").show();
                
            }else{
                alert('アカウントが違います。またはアカウント登録がされていません。');
                $('#paypal').attr('disabled',true);
                $('#kakunin').html('');
                $("#kakunin").hide();
            }
        },
        error: function( data ) {
            alert( '読み込み失敗' );
       }
   });
};

check_databaseメソッドにおいて、database_search.php を叩き、
取得した値を変数 data に代入させたのち、 , で区切って配列 datas に格納し、必要な値を取り出し、
hiddenフォームなどに値をセットしています。

ところで、呼び出し元では
password_cheack メソッドのあとに check_database メソッドでしたから、
これでは password_cheack メソッドの段階では #password2 に値はセットされていません。
password_cheack メソッドの引数が 0 なのは、パスワード判定がどうしても失敗することに困った末の苦肉の策なのかもしれません。


さて、「漏れる個人情報」の話に戻りましょう。
ここの非同期通信(Ajax)のメソッドを見るに、
http://yours-company.jp/School_Site/account/PHP/database_search.php
にアクセスすれば容易に値が取得できそうなことがわかります。

見ず知らずの人のアカウントを取得するのは倫理的に良くないので、会員登録をして試してみます。

f:id:nekonenene:20170526081334p:plain

このようにアカウントを取得してみました。

会員番号の値をもとに情報を取得するには search_no = 0,
メールアドレスの値をもとに情報を取得するには search_no = 1,
パスワードの値をもとに情報を取得するには search_no = 2,
ということがコードから読み取れますから、まずはメールアドレスで試してみましょう。

curl "http://yours-company.jp/School_Site/account/PHP/database_search.php?search_no=1&search_key=test@example.com"

このような値が返ってきます。

0,1,test@example.com,856,testtest,test@example.com,テスト 太郎,1

返ってきた値は、左から順に

  • エラーコード : 0
  • search_no : 1
  • search_key : test@example.com
  • 会員番号 : 856
  • パスワード : testtest
  • メールアドレス : test@example.com
  • 会員の姓名 : テスト 太郎

となっています。(一番右の 1 はダミー?)

パスワードが暗号化せずに保存されていることは、 #password2 との値の比較でパスワードの成否判定をしていたことから今さら驚かないですが、
もちろんこれも良くないですね。

ですが、一番良くないのは全会員情報が簡単に引き出せることにあります。

ブルートフォースアタック(総当たり攻撃)を仕掛けずとも、
連番で登録されている会員番号を1から順番に指定して取得を繰り返す、一行で書けるような簡単なシェルスクリプトを書くだけで、
全会員のメールアドレス、パスワード、会員の姓名を取り出せてしまいます。

5. 考えたこと

今回は極端な例ですが、思ったのは、
あまりいろんなサイトで真面目に会員情報を登録するのは怖いな、ということです。

大きな会社ですと情報漏えいはニュースになるくらいなのでまだいいのですが、
DTMで音源を買う関係で、海外サイトや、個人サイトで会員登録をすることも多く、
そういうところで情報漏えいが起きたところで、私(もしくはそのサイトの運営者)は気付くことがないので、ちょっと怖いなと思いました。

それから、JSコードは minify なり uglify をかけておくと、
多少ダメなコードでも、その難読性から少しは脆弱性対策になるな、と、
今回のコードが読みやすかったぶん感じました。

以上、セキュリティは気を付けないと顧客情報が大変って話でした。
ユーザー登録者としてもウェブ開発者としても、こういう話は明日は我が身です……。


ちなみに、フォームで任意のJavaScriptコードを実行できる問題もありました。

f:id:nekonenene:20170526091800p:plain