tag:crieit.net,2005:https://crieit.net/tags/%E8%84%86%E5%BC%B1%E6%80%A7/feed 「脆弱性」の記事 - Crieit Crieitでタグ「脆弱性」に投稿された最近の記事 2018-10-31T12:53:51+09:00 https://crieit.net/tags/%E8%84%86%E5%BC%B1%E6%80%A7/feed tag:crieit.net,2005:PublicArticle/14505 2018-08-14T23:07:38+09:00 2018-10-31T12:53:51+09:00 https://crieit.net/posts/3007e75a4752e022ab2ad08cd46004de 「世界最悪のログイン処理コード」ではない可能性は無いのか? <p>先日「世界最悪のログイン処理コード」が話題になった。</p> <blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">世界最悪のログイン処理コード。実際のサービスで可動していたものだとか……<a target="_blank" rel="nofollow noopener" href="https://t.co/C2bG93ZCkj">https://t.co/C2bG93ZCkj</a> <a target="_blank" rel="nofollow noopener" href="https://t.co/EfVNAEslrn">pic.twitter.com/EfVNAEslrn</a></p>— はっしー@海外プログラマ🇳🇿元社畜 (@hassy_nz) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hassy_nz/status/1027890455940198400?ref_src=twsrc%5Etfw">2018年8月10日</a></blockquote> <p>ただ、開発者がその脆弱性を理解した上で、ちゃんと対処を行っており問題ない状態である可能性はないかを考えてみた。</p> <h2 id="一番の問題"><a href="#%E4%B8%80%E7%95%AA%E3%81%AE%E5%95%8F%E9%A1%8C">一番の問題</a></h2> <p>今回のコードで一番問題になっているのはやはりここだろう。</p> <pre><code class="javascript">var accounts = apiService.sql( "SELECT * FROM users" ); </code></pre> <p>生のSQLをサーバーに送って実行した結果をクライアント側で取得できるようにしていることで、第三者があらゆる情報を取得できてしまう脆弱性と、クライアント側にて大量のメモリ使用を強制させて負荷を与えるという問題をたった三行で想像させてしまう恐ろしいコードだ。</p> <p>でも、ちょっと考え方を変えるとそうではない可能性もあるということが分かる。</p> <h3 id="SQL文をフィルタリングしている"><a href="#SQL%E6%96%87%E3%82%92%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B">SQL文をフィルタリングしている</a></h3> <p>もしサーバー側で送られてきたSQLをフィルタリングして、許可していないSQLを弾いている場合はデータベースのあらゆる情報をとれてしまうということはない。</p> <h3 id="そもそもSQLをそのまま実行しているわけではない"><a href="#%E3%81%9D%E3%82%82%E3%81%9D%E3%82%82SQL%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%82%8F%E3%81%91%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84">そもそもSQLをそのまま実行しているわけではない</a></h3> <p><code>SELECT * FROM users</code>というSQL文を引数として渡しているが、これを必ずしもサーバー側でそのまま実行しているとは限らない。そもそも<code>apiService.sql</code>というメソッドが引数だけを使って処理をしているとは限らない。</p> <p>色々総合すると下記の様な感じになっている可能性もある。</p> <p>JavaScript側</p> <pre><code class="javascript">class ApiService { sql(query) { const response = $.ajax({ url: "/api/sql", type: "get", async: false, data: { username: $("#username").val(), password: $("#password").val(), sql: query } }); return response.result; } } </code></pre> <p>サーバー側</p> <pre><code class="php">$methods = [ "SELECT * FROM users" => "getLoginUser", : ]; $this->{$methods[$request["sql"]]}($request); </code></pre> <p><code>getLoginUser</code>の中で<code>SELECT id, nickname FROM users WHERE username = '$username' AND password = '$password'</code>みたいなのを実行して結果を返す感じ。</p> <p>こんな感じであればセキュリティ的にもメモリ的にも全く問題はない。</p> <p>ただしもちろんAPIのURLを別にすればいいだけでSQL文でフィルタリングする必要性も全く無いし、誰がどう見てもSQLを直接動かしているようにしか見えないので実装的にはとんでもない話ではあると思う。</p> <h2 id="生パスワードを使ってる問題"><a href="#%E7%94%9F%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%8B%E5%95%8F%E9%A1%8C">生パスワードを使ってる問題</a></h2> <p>次に問題となるのは入力されたパスワードをそのまま使っている、つまりデータベースにも生のパスワードが保存されているのではないか疑惑。これに関しては先程のようにサーバー側で単なるSQLを直接実行しているわけではないという前提であれば疑惑を回避できる。</p> <p>ただ、<code>account.password === password</code>という処理があるせいで、やはり生パスワードを使っていないとおかしいのでは、という話になってしまう。</p> <p>ただここは一応<code>$("#password").val()</code>は必ずしも#passwordが入力欄とは限らないので、例えば#password_inputに入力されたものを随時サーバーに送って、ハッシュ化したものを#passwordというhiddenに入れておく、という可能性があり、それであれば特にその部分の問題はなくなる。</p> <p>もちろんこのコードにするためにわざわざ通信して変換しているという処理は理解し難い。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>一応「世界最悪のログイン処理コード」であることを回避することができるような考え方は不可能ではなさそうだが、そのかわり今度は人としての優しさを失ったコードになってしまいそう。</p> だら@Crieit開発者