1. ホーム
  2. node.js

[解決済み】node.jsでセキュアなREST APIを実装する方法

2022-04-12 12:55:25

質問

node.js、express、mongodbを使ったREST APIの企画を始めています。このAPIは、ウェブサイト(公開および非公開エリア)、そしておそらく将来のモバイルアプリのためのデータを提供します。フロントエンドはAngularJSで開発される予定です。

ここ数日、REST APIのセキュリティについていろいろと読みましたが、最終的な解決策にたどり着けません。私が理解している限りでは、基本的なセキュリティを提供するためにHTTPSを使用することです。しかし、私はそのユースケースでAPIをどのように保護することができますか?

  • Webサイト/アプリの訪問者/ユーザーのみが、Webサイト/アプリの公開領域のデータを取得することができる

  • 認証され許可されたユーザーのみが、プライベートエリアのデータを取得することができます(また、ユーザーが権限を与えたデータのみ)。

今のところ、アクティブなセッションを持つユーザーのみにAPIを使用させることを考えています。ユーザーの認証にはパスポートを使用し、許可には自分自身で何かを実装する必要があります。すべてHTTPSの上にあります。

どなたかベストプラクティスや経験を教えていただけませんか?私の「アーキテクチャ」に不足があるのでしょうか?

解決方法は?

私も同じような問題を抱えています。私が構築しているウェブサイトは、携帯電話やブラウザからアクセスできるため、ユーザーがサインアップ、ログイン、いくつかの特定のタスクを実行できるようにするためのAPIが必要です。さらに、スケーラビリティをサポートする必要があり、同じコードが異なるプロセス/マシンで実行される必要があります。

ユーザーはリソースを作成することができるため (別名 POST/PUT アクション)、API を保護する必要があります。oauthを使用するか、独自のソリューションを構築することができますが、パスワードが本当に簡単に発見された場合、すべてのソリューションが破られる可能性があることに留意してください。基本的な考え方は、ユーザー名、パスワード、トークン(別名:アピトークン)を使ってユーザーを認証することです。この apitoken は次のようにして生成します。 ノードユーアイディー を使用し、パスワードをハッシュ化することができます。 pbkdf2

次に、セッションをどこかに保存する必要があります。プレーンなオブジェクトでメモリ上に保存すると、サーバを一度終了して再度起動したときに、セッションが破壊されてしまいます。また、これではスケーラブルではありません。マシン間の負荷分散のために haproxy を使用したり、単に workers を使用したりすると、 このセッションの状態はひとつのプロセスに保存されることになり、 同じユーザーが別のプロセスやマシンにリダイレクトされると、 再び認証が必要になります。そのため、セッションを共通の場所に保存しておく必要があります。これは通常、redisを使用して行われます。

ユーザーが認証されると(ユーザー名+パスワード+アピトークン)、セッション用の別のトークン、別名アセスストークンを生成します。ここでもnode-uuidを使用します。ユーザーにaccessstokenとuseridを送ります。userid(キー)とaccessstoken(値)はredisに保存され、1時間などの有効期限を持つ。

これで、ユーザーが rest api を使って何か操作をするたびに、userid と accesstoken を送信する必要があります。

ユーザーがrest apiを使ってサインアップできるようにする場合、新規ユーザーはサインアップ時にapitokenを持っていないため、admin apitokenでadminアカウントを作成し、モバイルアプリに保存する必要があります(ユーザー名+パスワード+apitokenを暗号化する)。

Webでもこのapiを使いますが、apitokensを使う必要はありません。Redisストアでexpressを使うか、上記と同じ手法でapitokenのチェックを回避してuserid+accesstokenをcookieでユーザーに返せばいいのです。

プライベートエリアがある場合、認証時にユーザー名と許可されたユーザーを比較します。また、ユーザーにロールを適用することもできます。

概要を説明します。

apitokenを使わない代替案としては、HTTPSを使用し、Authorizationヘッダでユーザ名とパスワードを送信し、ユーザ名をredisにキャッシュする方法があります。