Line 1: Error: Invalid Blog('by Esehara' )

または私は如何にして心配するのを止めてバグを愛するようになったか

>> Zanmemo

あと何かあれは 「esehara あっと じーめーる」 か @esehara まで

最近、ソーシャル系Webアプリで見たダメなAPIパターンについて

はじめに

 多くのWebサービスが、ブラウザ上で、JavaScriptの連携を行ったり、あるいはモバイルアプリとの連携のために、サービスの操作を行うためのAPIを作っている場合がありますが、多くの場合、そのあたりのAPIで、クリティカルではないのだけれど、ちょっと困るかたちのAPIになっていたりします。

 自分は、そういうAPIをいじって遊ぶのが趣味で、Webサービス開発者としては多少迷惑なユーザーかもしれません。その中で、幾つか、初歩的だけど意図しない挙動になりがちな部分についてメモしておきます。

サービスでのアクションを行うユーザーのIDを直接渡してしまっているパターン

 こういうタイプのAPIは、1年に一度くらいなのですが、本当にたまに見ます。具体的には下のようなURLだったりします。

http://example.com/follow?user_id=333&follow=999

 普通に考えて「ありえない」と思うAPIかもしれませんが、過去に2回ほど見ています。推測するに、プロトタイプで作ったAPIでそのままランニングを行ってしまったために、こういうAPIになってしまった可能性があります。また、クライアントを実装する上において、簡単に実装とした結果、こういう仕様になってしまった可能性もあります。

 このAPIの作りが非常にまずいのは、フォローとフォロワーを任意的に操作できてしまう点にあります。他人の行動はともかくとして、任意のユーザーが他人から、そのアクションを指定してできてしまう場合、ユーザーとしては端的に意図しない行動がされているという状態は、心情が悪くなってしまいます。酷いものになると、すべてのアクションに対して、ユーザーIDを渡す仕組みになってしまっているため、あらゆる操作が他人から操作できてしまうという非常にまずい状態になっていたりします。

 あえて言う必要はないかもしれませんが、一つの方向としては、ユーザーに対して、任意のランダム文字列にあたるトークンなりを発行し、少なくともあるユーザーを操作するためのIDを推測させないほうが望ましい。少なくとも、数字や、ログインIDを使うと、簡単に推測できてしまうため、そのユーザーの行動を簡単に操作できることになってしまいます。

未来のユーザーに対してアクションを発行できてしまうパターン

 これも幾つかのサービスで見た挙動。特にフォローという概念のSNSだと、たまに見られる。そして、こういう挙動をする場合、フォロー先のUserが連番IDで管理されていたりするから余計厄介だったりする。

 このパターンにおいて起こりうる挙動としては、端的に未来のユーザーに対してフォローが出来るため、登録時において、いきなりフォローが一人存在してしまっているという状態になりうるし、また将来のユーザーに対して、イベントが発生してしまう可能性もある。これは、登録時にいきなり部外者が登録できてしまうために、気持ち悪く感じられてしまうことがある。

 これについては、存在しないユーザーに対してフォローが出来てしまうことについては、確かに問題はあるものの、即サービスに影響があるかというとそうではない。問題は、数字で未来のユーザーが指定できる場合、確実にそのIDがプラスされたユーザーが指定できるのが問題になる。少なくとも、文字列の場合、そういう名前のユーザーが登録されるかどうかは予測できない。

 これを防ぐためには、アプリ側のコードで、そのユーザーがいるかどうかを調べるようにするか、データベース側で、「このIDが存在しない場合は、フォローを増やすクエリーを受け付けない」といったような設定を行う必要があるでしょう。

なぜこうなっちゃうのパターン: クライアントパラメーター信頼しすぎアンチパターン

 これらのAPI設計、しかもおそらくサーバーサイド側ではかなり基礎的であるような部分が欠けてしまう原因の一つとして、おそらく「サーバーサイドが、クライアント側の投げるパラメーターを信頼しすぎる」ような設計が問題になっているように感じます。おそらく、「クライアント側でバリデートしている」というのもあるかもしれません。

 個人的には、クライアント側でバリデートしすぎるのはお勧めではありません。少なくとも「ある値を受け入れるべきかどうか」は、サーバー側のロジックとして、書いておくべきでしょう。クライアント側は、そのクライアント内の挙動のみを制御できるのであって、そこから外れたリクエストを食い止めることはできません。そして、あるクライアントのみを受け取るように強制することは現実的ではない気がします。とすると、やはりそのような「こうであってはいけない」というものは、サーバー側でちゃんと書いておくべきである、と思います。

まとめ: サーバーサイドは投げられる値を信頼しないようにする

 これは結構意外だったと思うのですが、思うところもあります。基本的に「自分たちが投げる値をどうするのか」という部分に注目しすぎているのかなとは思います。そうすると、「投げる値の正しさ」ばかりに注目しすぎなのですが、しかしそれは往々にして投げる側の都合であって、受け入れ側の都合というのも同様にあったりします。そして、恐らくこれは、サーバー側とクライアント側が書けたとしても、どちらかというとクライアント側開発者だと、そういう風に考えてしまう節があるのかもしれません。

 とはいえ、サーバーサイド側はやはり、どこかちょっといじわるな状況を理解して、そういう「いじわる」をするとどういう風になるのか、ということを考える必要があるという側面があるのかなという気がします。もちろん、そういうユーザーはかなり少ないのですが、それでも考えておく必要がある問題だと思いますし、詳しい人がいなければ、レビューを受けるのもいいかもしれません。