安全性 - 访问令牌最佳做法

时间:2017-02-12 20:28:18

标签: node.js security authentication encryption access-token

我目前正在开发一个简单的API,它将成为我应用的后端。我现在正在设计我的数据结构,并对安全最佳实践有一些疑问。

项目背景

项目是用node.js

编写的

由于这将是一个API(带有一些受保护的方法),我认为最好使用基于访问令牌的身份验证系统。 (用户登录并检索其令牌,然后可以使用它来访问受保护的方法)

数据的结构使每个用户都拥有唯一的用户名和唯一的令牌。出于这个问题(和我的项目)的目的,让我们假设这个令牌永远不会改变。但是它以纯文本格式存储在数据库中。

要确保有权访问数据库的人只需复制此令牌即可直接访问API,我会在发送令牌之前对其进行编码。这样,实际的身份验证令牌与存储在数据库中的令牌不同,但服务器可以解码auth_token以重新创建令牌并等等等等。

然而,有权访问数据库的人只能自己对令牌进行编码...而且我试图找出是否有针对此问题的解决方法。

我的问题:

我试图找出是否有更安全的方法来做到这一点。所以请告诉我你的所有想法和最佳实践规则等。

BTW,我考虑过使用盐渍哈希作为加密,但这会产生完全相同的问题,以便将存储的令牌与您需要存储盐的实际访问令牌相匹配,因为您不能恢复这样的加密。存储salt使人们可以访问数据库,从而创建实际的访问令牌......

PS: 我自己尝试创建整个身份验证过程,因此请不要提出passport.js之类的建议。我的意思是那里有很棒的帮助工具,我只想手动完成这个工作。

[更新]项目背景

在这里,我将尝试为该项目绘制更多背景。 这确实是一个高中信息学项目。 (如下所述) 这个想法很简单:一个TODO应用程序,你可能听说过node-todo,基本上就是这样。

这是一项小组作业,小组成员的专业水平差异很大。 (有些人只做过HTML和(某些)CSS,其他人做了一些JS)我已经负责创建应用程序的背面(与数据库交互的API),因为没有其他组成员知识。由于其他小组成员并非全部经验丰富,我不知道前端会是什么样子。 (我最好的猜测是从网络应用开始)

所以基本上我想创建一个适用于每个客户端的后端,它应该是独立的。也就是说,客户端不会托管在同一台服务器上(很可能测试只在本地进行)。

  

面向API。现代应用程序在任何地方组合和公开API。它们以开放的Web技术为基础,使用REST,XML和JSON,使所有类型的设备和客户端都可以轻松地使用数据。任何可见的服务或数据都有一个无头的" API对应物,以便可以提供替代视图。在许多情况下,现代应用程序公开的API构成了公共第三方开发人员社区的基础,该社区支持对驱动公司业务的核心数据和服务进行混搭,插件和创新。   〜zdnet.com

3 个答案:

答案 0 :(得分:1)

如果您不介意在服务器上保存状态,可以使用哈希表来保存令牌:

用户登录后,您会生成随机哈希。此哈希用作表中的键。您可以通过验证已使用的令牌确实是表中的键来验证传入的请求。

为了能够识别登录的用户,您应该将用户标识符(如用户电子邮件)添加到已保存的对象中。您可能还希望将已使用的IP地址和到期日期添加到此对象,以进一步提高安全性。

通过使用此技术,您无需在数据库中保存令牌:)仅使用散列密码

(您可能希望立即清除哈希表以删除过期的主菜)

祝你的项目好运,并为我拉扯拉<

答案 1 :(得分:0)

我通常只使用jwt自己的腌制过程。我根本不在我的数据库中存储令牌,但只是用它来存储用户的信息并设置8小时左右的到期时间。这样,你就不需要了在db中存储令牌,您只需解码每个请求上的令牌并访问存储在其有效负载中的userID。唯一的缺点是,如果有人窃取别人的标记,但您可以在有效负载中添加IP地址,并确保客户端IP与存储在令牌中的IP相同。

我没有使用护照,但是我使用bcrypt进行密码加密,使用JWT作为我的代币。对不起,如果这不是你要找的东西。欢呼声。

这是我的auth库:

(function() {
  var bcrypt = require('bcrypt-nodejs'),
    jwt = require('jsonwebtoken'),
    helpers = require('../lib/helpers.lib.js');

  var JWT_SECRET = 'XXXXX';

  module.exports = function() {
    var self = this;

    //Returns true if valid token given, false otherwise
    self.validToken = function(token) {
      if (token) {
        try {
          var decoded = jwt.verify(token, JWT_SECRET);
          return true;
        } catch (err) {
          // console.log(err)
          return false;
        }
      } else {
        return false;
      }
    };

    self.decodeToken = function(token) {
      if (!token) {
        return null;
      }
      try {
        var decoded = jwt.verify(token, JWT_SECRET);
        return decoded;
      } catch (err) {
        // console.log(err)
        if (err.name == "TokenExpiredError") {
          return 'expired';
        }
        return null;
      }
    };

    self.createToken = function(payload, expires) {
      options = { "expiresIn": ((expires) ? '2d' : '14d') };
      return jwt.sign(payload, JWT_SECRET, options);
    };

    self.hashPassword = function(password) {
      return bcrypt.hashSync(password)
    };

    self.comparePassword = function(plainTextPassword, hashedPassword) {
      return bcrypt.compareSync(plainTextPassword, hashedPassword);
    };

    return self;
  };
}());

答案 2 :(得分:0)

记住多件事: - 你看过Firebase吗? - 比如双因素身份验证(例如Speakeasy或authy)?

你没有提供太多有关项目背景的细节,我从先生那里了解到。 Moorlag认为它与高中信息学有关。因此,如果您想要进行概念验证(例如,对于Profielwerkstuk(荷兰学校的高中毕业论文)),您将有不同的要求,而不是“只是实现应用程序”,您希望在Play /中发布App Store当然。

我的一些小学生两周前做了一个关于Firebase的研讨会,然后你不需要担心这样的事情,工作真的很棒(注意:Firebase是NoSQL所以忘记规范化;))。如果您想对它进行研究,我会找到有关双因素身份验证的详细信息,还可以查看TLS / HTTPS(让我们加密?!yay!)。