我曾帮助一家小型非营利组织创建了一个很酷的“匿名”帮助专线,客户可以在其中向手机号码发送SMS问题,组织可以在不知道客户是谁的情况下做出回应。它被证明是对组织非常有用的工具。我正在从头开始重写它,并正在寻求有关如何处理它的匿名性方面的建议。
v1的工作方式是简单地加密/解密客户端电话号码,并使用'aes-256-ctr'将其用作数据模型中的客户端ID。由于非营利组织的员工/领导层无法访问加密密钥,因此他们可以合理地声称无法访问任何p.i.i。没有被客户自愿披露。当他们向客户端发出消息响应时,我只需要解密客户端ID即可获得我需要的电话,以便分派消息。
v1加密策略:
export const encrypt = (text) => {
const cipher = crypto.createCipher(algorithm, password);
let crypted = cipher.update(text, 'utf8', 'hex');
crypted += cipher.final('hex');
return crypted;
};
export const decrypt = (text) => {
const decipher = crypto.createDecipher(algorithm, password);
let dec = decipher.update(text, 'hex', 'utf8');
dec += decipher.final('utf8');
return dec;
};
不过,最近我一直在收到控制台警告,因为在使用createCipher而不是createCipheriv来利用初始化向量时,新节点版本将输出警告。在我的v2重写中,我将其切换到createCipheriv,但这具有“随机化”加密输出的作用,并且破坏了我依赖加密电话号码作为可靠,一致的客户端ID的能力。能够可靠地对客户端消息进行分组是在UX中提供会话视图的重要要求。
我应该如何正确加密标识的电话号码,以便只有我可以在发送消息时解密该电话号码,并且仍然具有某种一致的内部ID来对消息进行分组?我不必依赖加密的电话号码作为客户端ID,但是我无法想到任何可靠的替代方法(通过某种形式的查找表)。如果可能的话,我不想在没有I.V的情况下使用createCipher。如果不是最佳做法。
我应该注意,此应用程序未处理任何法律敏感信息或类似的高风险内容。我可能会逃避将未加密的电话号码存储在数据库中,而只是不将其公开给前端并保持匿名性,如果有合理的解决方法,我真的不喜欢这个想法。
有什么想法吗?
答案 0 :(得分:1)
您应该为每个新客户端生成一个新的随机(或UUID样式)客户端ID。这样做的好处是,您可以继续使用安全的加密方法,并且仍然可以快速识别和查找用户。
如果您希望电话号码字段充当唯一的查找,只需获取电话号码的HMAC并将其用于查找(以及存储加密)-永远无法解密,并且可以保证在给定键下对同一电话号码的调用之间保持一致。
编辑:要迁移现有数据,对于每条记录,都应获取client_id(当前为加密的电话号码),对其进行解密,HMAC,然后将结果存储在新列中。然后,生成一个新的ID,并将其设置为client_id。这样可以通过实际的client_id和电话号码进行查找。