所以我正在使用UNTIS后端在meteor中编写时间表应用程序。我现在面临的问题是,每次向服务器发出请求时,我都不希望每个用户重新输入密码。有时我甚至不能(例如在早上6点检查第一课是否都没有取消)。
问题是,普通需要密码。因此,密码必须在服务器上的某个位置可以正常访问。
答案 0 :(得分:1)
我创建了一个Meteor设置文件:
/development.json
{
"ENCRYPT_PASSW_ENCRYPTION_KEY": "*some long encryption key*",
"ENCRYPT_PASSW_SALT_LENGTH": 32,
"ENCRYPT_PASSW_USER_KEY_LENGTH": 32,
"ENCRYPT_PBKDF2_ROUNDS": 100,
"ENCRYPT_PBKDF2_DIGEST": "sha512",
"ENCRYPT_PASSW_ALGORITHM": "aes-256-ctr"
}
为了能够在流星应用程序中使用这些设置,您必须像这样开始流星:meteor run --settings development.json
旁注:当然你必须添加自己的参数。这些只是开发设置。您必须根据数据的重要性选择自己的参数。 (应选择PBKDF2_ROUNDS以适合您的主机系统。我已阅读somewhere哈希应该至少 241毫秒)
一些服务器端功能:
// server/lib/encryption.js
const crypto = require("crypto");
// generate a cryptograhpically secure salt
// with the length specified in the settings
generateUserSalt = function (length = Meteor.settings.ENCRYPT_PASSW_SALT_LENGTH) {
return crypto.randomBytes(length).toString("base64");
}
// encrypt a password with a key, derived from the
// application key plus the users salt
encryptUserPass = function (uid, pass, salt = false) {
const key = getUserKey(uid, salt),
algorithm = Meteor.settings.ENCRYPT_PASSW_ALGORITHM,
cipher = crypto.createCipher(algorithm, key);
return cipher.update(pass,'utf8','hex') + cipher.final('hex');
}
// decrypt a password with the same key
decryptUserPass = function (uid, ciphertext, salt = false) {
const key = getUserKey(uid, salt),
algorithm = Meteor.settings.ENCRYPT_PASSW_ALGORITHM,
decipher = crypto.createDecipher(algorithm, key);
return decipher.update(ciphertext,'hex','utf8') + decipher.final('utf8');
}
// generate the user-specific key that derives from
// the applications main encryption key plus the users
// specific salt. this is only needed in this scope
function getUserKey (uid, salt = false) {
// if no salt is given, take it from the user db
if (salt === false) {
const usr = Meteor.users.findOne(uid);
if (!usr || !usr.api_private || !usr.api_private.salt) {
throw new Meteor.Error("no-salt-given", "The salt from user with id" + uid + " couldn't be located. Maybe it's not set?");
}
salt = usr.untis_private.salt;
}
const systemKey = Meteor.settings.ENCRYPT_PASSW_ENCRYPTION_KEY,
rounds = Meteor.settings.ENCRYPT_PBKDF2_ROUNDS,
length = Meteor.settings.ENCRYPT_PASSW_USER_KEY_LENGTH,
digest = Meteor.settings.ENCRYPT_PBKDF2_DIGEST;
const userKey = crypto.pbkdf2Sync(systemKey, salt, rounds, length, digest);
return userKey.toString('hex');
}
现在我可以用这样一个唯一的密钥加密每个用户的密码:
// either with generating a salt (then the uid is not needed)
let salt = generateUserSalt(),
encPass = encryptUserPass(0, pass, salt);
// or when the user already has a salt (salt is in db)
let encPass2 = encryptUserPass(uid, pass);
解密也很简单:
let pass = decryptUserPass(0, passEnc, salt);
// or
let pass2 = decryptUserPass(uid, passEnc);
当然我知道,这在安全性方面仍然非常糟糕(在服务器上存储可以反转为用户密码的内容)。我认为这是可以的原因:
每个用户密码都加密如下:
AES(password, PBKDF2(global-encryption-key + salt))
这意味着:
为什么我认为这是一个很好的解决方案:
因此,您应该选择一个相当大的全局加密密钥。