質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

1回答

2500閲覧

APIトークンの効率の良い実装方法

Kenelaoy

総合スコア50

セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

1グッド

5クリップ

投稿2019/01/06 18:49

編集2019/01/06 18:56

現在使っているのが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はトークンの生成に使われない値 192021

#疑問
1つ目に疑問なのが、いくらランダム生成した値とはいえ、APIトークンの素となる値がユーザーと同じテーブルに存在してていいのかというところです。
データベース(Postgresql)とRailsは同一の物理サーバー内で完結していて、データベースのUserテーブルとDotenvで管理している暗号鍵を入手しなければAPIから期待通りの応答を得ることは難しいと思われますし、これらを奪取されるのはまた別の次元の問題なので、Railsだけ見れば問題ないのではないかと思ってこの実装にしていますが、何とも言い難い気持ち悪さが残っています・・・

これは果たして妥当なDB設計なのでしょうか、もっと良いDB設計があればご教授頂きたいです。


2つ目にわざわざ暗号化が必要なのかというところです。
暗号化をしている理由としては、同一暗号鍵と同一平文の組み合わせでも、暗号化を実行する度に結果が変わるので推測が難しくなるとの考えがあります(もしかしたらここからして愚かなのかもしれませんが・・・)

現状、この実装でセキュリティ的にもパフォーマンス的にも不便が起きたことはないのですが、それはあくまでユーザーが圧倒的に少ないからであって、多くなるにつれて暗号化がボトルネックになってパフォーマンスが低下するということがあってほしくはありません。
もし暗号化よりもパフォーマンスの良い方法があればご教授頂きたいです。

まとめ

  • どこから間違ってるのか分からないくらい、「ホントにこれ合ってるの?」という実装がとても多いです・・・
  • APIトークンの生成に限らず、助言などをいただけると大変ありがたいです・・・

宜しくお願いしますm(_ _)m
質問などあれば、随時返信・編集しますので、言っていただければと・・・

kamedd👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ockeghem

2019/01/16 13:33

回答しようかなと思いつつ、元のプログラムを読み解くのが面倒なので、結局手がつかないのですよね。もう少し、解決すべき問題を端的に提示していただけないでしょうか? (回答を保証するものではありません)
guest

回答1

0

APIトークンの素となる値がユーザーと同じテーブルに存在してていいのか

トークンで何ができるかによるかも
トークンでユーザテーブルがみられるだけならトークンを分けても片方がもれればどちらももれるので分ける意味はないかと

このトークンで他のもっとみられたくないテーブルアクセスもできるのであれば
分けることでユーザテーブルの情報はもれたけどもっと重要な情報は守られるということはあるかも

これらを奪取されるのはまた別の次元の問題

よくあるのはユーザ入力をクエリの中にいれてしまう
いわゆるSQLインジェクションでクエリの脆弱性をつかれたときにトークンが流出してしまう

あと Rails だとモデルとカラムが連携してるので検索した意図的に select しないと
モデルに自動的にトークン情報も含まれるので
めったにおきないエラーメッセージにレコードのダンプを返すようにしてそのまま忘れてたりとか

それから一部サービス開発を第3社に提供する場合にユーザ情報はみてもいいけどトークンは見られたくないみたいな場合があるかどうか
あるいはバイトや新人にテーブル操作はしてもいいけど認証情報はさわらせたくないとか

分けておいたほうがそういう細かい権限の設定やバグを回避できる場合もあるかも

わざわざ暗号化が必要なのか

暗号化というよりは環境を識別する必要があるかどうかではないですか
たとえばステージングとプロダクションがあってステージングで作ったトークンで本番環境でアクセスできてしまうのがいいかどうか
あるいは別サービスが同じデータベースを見ているとか
それがかまわないのであれば暗号化する必要はないと思います

思いつくのはこのくらいです

Rails だったら自分でトークン管理しなくても Gem いれて1行かくだけで使える認証システムがいくつかあるんじゃないかな
自分はいれたことがないので詳しくないですが

投稿2019/01/17 07:05

編集2019/01/17 07:07
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問