LoginSignup
0
0

More than 5 years have passed since last update.

現場のSails.js #4 セキュリティ関連

Posted at

概要

弊社では一部の社内プロジェクトでSails.jsを利用しています。その中で得られたベストプラクティスやらバッドプラクティスをまとめていこうと思います。
第4回はセキュリティに関する設定を色々と。

動作環境

node.js v0.12.7
Sails.js v0.11.2
sails-mysql v0.11.0

blueprintの無効化

Sails.jsにはblueprintという便利な機能があり、例えばControllerに何も書かなくてもでGET /hogeというリクエストで自動的にHogeモデルの一覧をGETすることが出来たり、/api/controllers/HogeController.js#findというメソッドに自動的にルーティングしてくれたりします。
blueprintはプロトタイプを作成するときには非常に便利なのですが、実際の運用を考えると意図しないAPIを公開する可能性があり、セキュリティリスクが高まります。そのため、サービスの公開前にはOFFにすることをオススメします。

js/config/blueprint.js
module.exports.blueprints = {
  actions: false,
  rest: false,
};

そして/config/routes.jsに必要なルーティングを全て記述します。

js/config/routes.js
module.exports.routes = {
  /***************************************************************************
   *  Views
   ***************************************************************************/
  'GET /': 'ArticleController.top',

  /***************************************************************************
   *  API
   ***************************************************************************/
  'POST /api/article/:article/favorite': 'api/ArticleController.favorite',
};

policyの設定

Sails.jsはpolicyという機能でControllerのメソッドへのアクセスを制限出来るようになっているため、ログインを伴うアプリの場合は積極的に活用しましょう。

/config/policies.js
module.exports.policies = {
  '*': true,

  /***************************************************************************
   *  Views
   ***************************************************************************/
  'ArticleController': {
    '*': true,
    'favorite': 'sessionAuthView'
  },

  /***************************************************************************
   *  APIs
   ***************************************************************************/
  'api/ArticleController': {
    '*': false,
    'favorite': 'sessionAuthApi',
  }
};

API/ViewControllerで未ログイン時に行いたい処理が違うので、以下のようにsessionAuthView/sessionAuthApiという2つのpolicyファイルを使用します。

api/policies/sessionAuthView.js
module.exports = function(req, res, next) {

  // User is allowed, proceed to the next policy,
  // or if this is the last policy, the controller
  if (req.user) {
    return next();
  }

  // User is not allowed
  // Viewへのアクセスの場合はリダイレクト
  sails.log.warn('Unauthorized user access denied, ' + req.originalUrl);
  return res.redirect('/');
};
api/policies/sessionAuthApi.js
module.exports = function(req, res, next) {

  // User is allowed, proceed to the next policy,
  // or if this is the last policy, the controller
  if (req.user) {
    return next();
  }

  // User is not allowed
  // APIの場合は403を返す
  return res.send(403);
};

Waterline#create, #update

セキュリティとは若干違いますが、システムの品質のためにService層で気をつけている箇所があります。Sails.jsのO/R Mapper、Waterlineはcreateupdateに渡したObjectを、再帰的に作成・更新する機能があります。
例えば、チャットサービスでRoomMessageという2つのモデルが存在する場合に以下のコードを実行できます。

Room.create({
  name: 'hoge',
  messages: [
    { text: 'Hello' }
  ]
}).exec();

// リレーションのあるレコードもまとめて生成される
// => Room: {id: 1, name: 'hoge'}、Message: {id: 1, room: 1, text: 'Hello'}

実際のシステムでも活用している機能ですが、コードのバグにより意図しないレコードを生成してしまう可能性があります。そのため、O/R MapperへのアクセスはService層で隠蔽し、Serviceに渡されたパラメータをフィルタしてWaterlineに渡すようにしています。

ArticleService.ts
class ArticleService {
  create(params: Object): Promise<any> {
    return new Promise((resolve, reject) => {
      Article.create(_.pick(params, ['title', 'body]).then(resolve, reject);
    });
  }
}

export = new SELECK.Services.ArticleService();

まとめ

Sails.jsのようなフルスタックのフレームワークは便利機能がたくさんあります。ただし、あまり考えずにシステムが作れてしまう分、よく理解していないと思わぬセキュリティホールやバグを埋め込んでしまう可能性があります。しっかりとフレームワークを理解し、大事な部分では「便利機能を使わない」という選択肢も検討しましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0