68

angularJS を使用して Web アプリの開発を開始しましたが、すべてが適切に保護されているかどうかはわかりません (クライアント側とサーバー側)。セキュリティは単一のログイン ページに基づいています。資格情報が正常にチェックされている場合、サーバーはカスタムの有効期限を持つ一意のトークンを返します。他のすべての REST API は、このトークンを介してアクセスできます。アプリケーション (クライアント) は、エントリ ポイントの例を参照します: https://www.example.com/home.htmlユーザーは資格情報を挿入し、一意のトークンを受け取ります。この一意のトークンは、AES またはその他の安全な技術を使用してサーバー データベースに保存されます。クリアな形式では保存されません。

これからは、AngluarJS アプリはこのトークンを使用して、公開されているすべての REST Api を認証します。

カスタム http Cookie にトークンを一時的に保存することを考えています。基本的に、サーバーが資格情報を検証すると、新しい Cookie Ex. が返されます。

app-token : AIXOLQRYIlWTXOLQRYI3XOLQXOLQRYIRYIFD0T

Cookie には、セキュアおよびHTTP のみのフラグが設定されています。HTTP プロトコルは、新しい Cookie を直接管理して保存します。連続する要求は、Cookie を管理して JavaScript で保存する必要なく、新しいパラメーターを使用して Cookie を提示します。リクエストごとに、サーバーはトークンを無効にし、新しいトークンを生成してクライアントに送り返します --> 単一のトークンでリプレイ攻撃を防ぎます。

クライアントが REST Api から HTTP ステータス401 の無許可の応答を受信すると、Angular コントローラーはすべての Cookie を消去し、ユーザーをログイン ページにリダイレクトします。

他の側面を考慮する必要がありますか?トークンを新しい Cookie 内に保存するか、localStorage に保存する方がよいでしょうか? 独自の強力なトークンを生成する方法に関するヒントはありますか?

編集(改善):

  • セッション トークン ジェネレーターとして HMAC-SHA256 を使用することにしました。有効期間は 20 分です。ランダムな 32 バイトの GUID を生成し、タイムスタンプを添付し、40 バイトのキーを提供して HASH-SHA256 を計算します。トークンの有効性が非常に低いため、衝突を取得することはまったく不可能です。
  • Cookie には、セキュリティを強化するためのドメインとパスの属性があります。
  • マルチログインは許可されていません。
4

4 に答える 4

55

https 経由でサーバーと通信する場合、リプレイ アタックの問題はありません。

サーバーのセキュリティ技術を活用することをお勧めします。たとえば、JavaEE には、すぐに使用できるログイン メカニズム、リソース (REST エンドポイント) の宣言型の役割ベースの保護などがあります。これらはすべて一連の Cookie で管理され、ストレージやストレージについて気にする必要はありません。有効期限。サーバー/フレームワークがすでに提供しているものを確認してください。

API をより幅広い利用者 (具体的に提供するブラウザー ベースの UI ではなく) や他の種類のクライアント (モバイル アプリなど) に公開することを計画している場合は、OAuth の採用を検討してください。

私の頭の上では、Angular には次のセキュリティ機能があります (さらに追加される予定です)。

CSRF/XSRF 攻撃

Angular は、CSRF保護のためのすぐに使えるメカニズムをサポートしています。$http ドキュメントをチェックしてください。サーバー側のサポートが必要です。

コンテンツ セキュリティ ポリシー

Angular には、 CSPが有効な場合に適用されるより厳密な JavaScript ランタイムと互換性のある式評価のモードがあります。ng-csp ドキュメントをチェックしてください。

厳密な文脈エスケープ

Angular の新$sce機能 (1.2+) を使用して、XSS 攻撃などに対して UI を強化します。これは少し便利ではありませんが、より安全です。こちらのドキュメントをご覧ください。

于 2014-01-16T19:21:46.597 に答える
10

これは、通常の Angular バージョンで実装できるクライアント側のセキュリティです。私はこれを試してテストしました。(私の記事はこちら:- https://www.intellewings.com/post/authorizationonangularroutes ) クライアント側のルート セキュリティに加えて、サーバー側でもアクセスを保護する必要があります。クライアント側のセキュリティは、サーバーへの余分なラウンド トリップを回避するのに役立ちます。ただし、誰かがブラウザを騙した場合、サーバー サーバー側のセキュリティは不正アクセスを拒否できるはずです。

お役に立てれば!

ステップ 1: app-module でグローバル変数を定義する

-アプリケーションの役割を定義する

  var roles = {
        superUser: 0,
        admin: 1,
        user: 2
    };

・アプリの不正アクセス経路を定義する

 var routeForUnauthorizedAccess = '/SomeAngularRouteForUnauthorizedAccess';

ステップ 2: 承認用のサービスを定義する

appModule.factory('authorizationService', function ($resource, $q, $rootScope, $location) {
    return {
    // We would cache the permission for the session, to avoid roundtrip to server for subsequent requests
    permissionModel: { permission: {}, isPermissionLoaded: false  },

    permissionCheck: function (roleCollection) {
    // we will return a promise .
            var deferred = $q.defer();

    //this is just to keep a pointer to parent scope from within promise scope.
            var parentPointer = this;

    //Checking if permisison object(list of roles for logged in user) is already filled from service
            if (this.permissionModel.isPermissionLoaded) {

    //Check if the current user has required role to access the route
                    this.getPermission(this.permissionModel, roleCollection, deferred);
} else {
    //if permission is not obtained yet, we will get it from  server.
    // 'api/permissionService' is the path of server web service , used for this example.

                    $resource('/api/permissionService').get().$promise.then(function (response) {
    //when server service responds then we will fill the permission object
                    parentPointer.permissionModel.permission = response;

    //Indicator is set to true that permission object is filled and can be re-used for subsequent route request for the session of the user
                    parentPointer.permissionModel.isPermissionLoaded = true;

    //Check if the current user has required role to access the route
                    parentPointer.getPermission(parentPointer.permissionModel, roleCollection, deferred);
}
                );
}
            return deferred.promise;
},

        //Method to check if the current user has required role to access the route
        //'permissionModel' has permission information obtained from server for current user
        //'roleCollection' is the list of roles which are authorized to access route
        //'deferred' is the object through which we shall resolve promise
    getPermission: function (permissionModel, roleCollection, deferred) {
        var ifPermissionPassed = false;

        angular.forEach(roleCollection, function (role) {
            switch (role) {
                case roles.superUser:
                    if (permissionModel.permission.isSuperUser) {
                        ifPermissionPassed = true;
                    }
                    break;
                case roles.admin:
                    if (permissionModel.permission.isAdministrator) {
                        ifPermissionPassed = true;
                    }
                    break;
                case roles.user:
                    if (permissionModel.permission.isUser) {
                        ifPermissionPassed = true;
                    }
                    break;
                default:
                    ifPermissionPassed = false;
            }
        });
        if (!ifPermissionPassed) {
            //If user does not have required access, we will route the user to unauthorized access page
            $location.path(routeForUnauthorizedAccess);
            //As there could be some delay when location change event happens, we will keep a watch on $locationChangeSuccess event
            // and would resolve promise when this event occurs.
            $rootScope.$on('$locationChangeSuccess', function (next, current) {
                deferred.resolve();
            });
        } else {
            deferred.resolve();
        }
    }

};
});

ステップ 3: ルーティングでセキュリティを使用する: これまでに行ったすべてのハードワードを使用して、ルートを保護します。

var appModule = angular.module("appModule", ['ngRoute', 'ngResource'])
    .config(function ($routeProvider, $locationProvider) {
        $routeProvider
            .when('/superUserSpecificRoute', {
                templateUrl: '/templates/superUser.html',//path of the view/template of route
                caseInsensitiveMatch: true,
                controller: 'superUserController',//angular controller which would be used for the route
                resolve: {//Here we would use all the hardwork we have done above and make call to the authorization Service 
                    //resolve is a great feature in angular, which ensures that a route controller(in this case superUserController ) is invoked for a route only after the promises mentioned under it are resolved.
                    permission: function(authorizationService, $route) {
                        return authorizationService.permissionCheck([roles.superUser]);
                    },
                }
            })
        .when('/userSpecificRoute', {
            templateUrl: '/templates/user.html',
            caseInsensitiveMatch: true,
            controller: 'userController',
            resolve: {
                permission: function (authorizationService, $route) {
                    return authorizationService.permissionCheck([roles.user]);
                },
            }
           })
             .when('/adminSpecificRoute', {
                 templateUrl: '/templates/admin.html',
                 caseInsensitiveMatch: true,
                 controller: 'adminController',
                 resolve: {
                     permission: function(authorizationService, $route) {
                         return authorizationService.permissionCheck([roles.admin]);
                     },
                 }
             })
             .when('/adminSuperUserSpecificRoute', {
                 templateUrl: '/templates/adminSuperUser.html',
                 caseInsensitiveMatch: true,
                 controller: 'adminSuperUserController',
                 resolve: {
                     permission: function(authorizationService, $route) {
                         return authorizationService.permissionCheck([roles.admin,roles.superUser]);
                     },
                 }
             })
    });
于 2014-08-24T21:45:08.510 に答える