現在使っているのがRailsなので、Railsをベースに質問させていただきます
#やりたいこと
Railsを使って主にスマホアプリで使うRESTful APIを開発しています。
その際、ユーザーのデバイスからの要求に基づいて新規でユーザー情報と紐付いたAPIトークンを発行し、デバイスに返しています。
ユーザー情報と紐付いて、それによって応答が変わるようになっていますが、その実装方法に疑問があります。
#現状
ユーザーのデバイスから新規登録の要求が送られると、まずデータベースにユーザーを登録します。
実装としてはこんな具合です(例)
Ruby
1require 'securerandom' 2require 'json' 3 4def register_user 5 new_user = User.new 6 new_user.name = params["name"] 7 new_user.user_id = params["email"] #API内部で識別に使用する名前 8 new_user.rand_id = SecureRandom.hex(16) #これを使ってトークンを生成する 9 new_user.save() 10 ・ 11 ・ 12 ・
そして、APIトークンを生成します
Ruby
1 encryptor = ActiveSupport::MessageEncryptor.new(ENV["encryption_key"], cipher: 'aes-256-cbc') 2 api_token = encryptor.encrypt_and_sign(new_user.rand_id) #ランダム生成したIDを暗号化する 3 render json:{"status" => "OK","token" => api_token} 4end
APIのリクエストに対しての認証は以下の通りです
Ruby
1def new_post 2 begin 3 encryptor = ActiveSupport::MessageEncryptor.new(ENV["encryption_key"], cipher: 'aes-256-cbc') 4 target_user = User.where(:rand_id => encryptor.decrypt_and_verify(request.headers["Authorization"]) 5 if !target_user.present? 6 raise 7 rescue 8 render json:{"status":"error","error_description":"Invalid Authorization"},status:403 9 return 10 11 12 post_data = JSON.parse(request.body.read) 13 if !post_data["title"].present? or !post_data["body"].present? 14 render json:{"status" => "error", "error_description" => "Invalid Paramater"},status:400 15 return 16 17 post_to_db = Post.new 18 post_to_db.user_id = target_user.user_id #内部識別用のIDはトークンの生成に使われない値 19 ・ 20 ・ 21 ・
#疑問
1つ目に疑問なのが、いくらランダム生成した値とはいえ、APIトークンの素となる値がユーザーと同じテーブルに存在してていいのかというところです。
データベース(Postgresql)とRailsは同一の物理サーバー内で完結していて、データベースのUser
テーブルとDotenvで管理している暗号鍵を入手しなければAPIから期待通りの応答を得ることは難しいと思われますし、これらを奪取されるのはまた別の次元の問題なので、Railsだけ見れば問題ないのではないかと思ってこの実装にしていますが、何とも言い難い気持ち悪さが残っています・・・
これは果たして妥当なDB設計なのでしょうか、もっと良いDB設計があればご教授頂きたいです。
2つ目にわざわざ暗号化が必要なのかというところです。
暗号化をしている理由としては、同一暗号鍵と同一平文の組み合わせでも、暗号化を実行する度に結果が変わるので推測が難しくなるとの考えがあります(もしかしたらここからして愚かなのかもしれませんが・・・)
現状、この実装でセキュリティ的にもパフォーマンス的にも不便が起きたことはないのですが、それはあくまでユーザーが圧倒的に少ないからであって、多くなるにつれて暗号化がボトルネックになってパフォーマンスが低下するということがあってほしくはありません。
もし暗号化よりもパフォーマンスの良い方法があればご教授頂きたいです。
まとめ
- どこから間違ってるのか分からないくらい、「ホントにこれ合ってるの?」という実装がとても多いです・・・
- APIトークンの生成に限らず、助言などをいただけると大変ありがたいです・・・
宜しくお願いしますm(_ _)m
質問などあれば、随時返信・編集しますので、言っていただければと・・・