简体   繁体   English

存储密码以登录第三方API

[英]Storing passwords to login to 3rd party APIs

I am writing a trading application using Node & Express for the backend. 我正在使用Node&Express为后端编写交易应用程序。 Each user will have their own login for the application itself, but in order for it to be useful the application also needs to login to the user's brokerage account. 每个用户都有自己的应用程序登录名,但是为了使其有用,应用程序还需要登录到该用户的经纪帐户。

The brokerage account in question has a REST API in which you POST the login and password for that system. 有问题的经纪人帐户具有REST API,您可以在其中发布该系统的登录名和密码。 That API does not offer SSO or OAuth as an option for authentication. 该API不提供SSO或OAuth作为身份验证的选项。 The only means to authenticate is POSTing the uid and password. 进行身份验证的唯一方法是发布uid和密码。

So there are two logins involved here: one to my application, and another completely separate login to the brokerage account. 因此,这里涉及两种登录:一种是我的应用程序登录,另一种是完全独立的经纪帐户登录。 Each of those logins uses a different user ID and password. 这些登录中的每一个都使用不同的用户ID和密码。

The problem I'm having is figuring out how to store the password for the brokerage account. 我遇到的问题是弄清楚如何存储经纪帐户的密码。 I understand that storing a password at all is a bad idea. 我知道完全存储密码是个坏主意。 But if all I store is a salted hash of the brokerage password, I wont be able to reverse that and get the actual password back. 但是,如果我存储的只是经纪人密码的盐渍哈希,我将无法撤消该密码并找回实际密码。 Hence, my application won't be able to login to the brokerage account unless the user enters that password again. 因此,除非用户再次输入该密码,否则我的应用程序将无法登录到经纪帐户。

(As an aside, there is another program that does this. https://dough.com requires the user to login to dough, and then you also have to login to TD Ameritrade. That logging in twice is what I'm hoping to avoid.) (顺便说一句,还有另一个程序可以做到这一点。https://dough.com要求用户登录面团,然后还必须登录TD Ameritrade。两次登录是我希望的避免。)

Is there a reasonable and secure way to store a password for this 3rd party API so that my app can login on the user's behalf without forcing the user to submit the password every time they use my app? 是否存在合理且安全的方法来存储此第三方API的密码,以便我的应用可以代表用户登录而无需强迫用户每次使用我的应用时都提交密码? I understand there are big security risks here. 我了解这里存在很大的安全风险。 If the answer is no, then I won't. 如果答案是否定的,那么我不会。

Edit & Obligatory - Really the solution is to not do this. 编辑与强制-真正的解决方案是不这样做。 While technically possible, it will almost certainly not be implemented correctly & will expose your users' passwords. 尽管在技术上可行,但几乎可以肯定它不会正确实施,并且会公开用户的密码。

Yes there is, but it's not incredibly easy & implementation is key. 是的,确实有,但是这并不是一件容易的事,实现是关键。 The JavaScript OpenPGPJS library is what you want. 您需要的是JavaScript OpenPGPJS库

In order for a somewhat secure system, your backend cannot be allowed to decrypt the password. 为了建立一个较为安全的系统,不允许您的后端解密密码。 This is where the JS library comes in, which provides PGP crypto via the browser. 这是JS库进入的地方,该库通过浏览器提供PGP加密。

You can base the PGP password off of the user password, or make them provide a new one for decryption. 您可以将PGP密码作为用户密码的基础,或者使它们提供新的密码进行解密。 Alternatively, you can generate random keys for the password encryption then create a master key with access to the random ones - encrypting the master with the user input. 或者,您可以生成用于密码加密的随机密钥,然后创建可以访问随机密钥的主密钥-使用用户输入对主密钥进行加密。

Whichever method you go with you will either need to have them enter the password in order to decrypt the record when needed, or add their password into their local session. 无论采用哪种方法,都需要让他们输入密码以便在需要时解密记录,或者将他们的密码添加到他们的本地会话中。 The former is secure and the latter has obvious security implications. 前者是安全的,而后者则具有明显的安全隐患。

Simple string encrypt using a password as provided by the examples: 如示例所提供的,使用密码对简单字符串进行加密:

var options, encrypted;

options = {
    data: 'Hello, World!',      // input as String
    passwords: ['secret stuff'] // multiple passwords possible
};

openpgp.encrypt(options).then(function(ciphertext) {
    encrypted = ciphertext.data; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
});

Decrypt: 解密:

options = {
    message: openpgp.message.readArmored(encrypted), // parse armored message
    password: 'secret stuff'                         // decrypt with password
};

openpgp.decrypt(options).then(function(plaintext) {
    return plaintext.data; // 'Hello, World!'
});

I think you have a few options, and the decision you choose should depend on the risk you want to take. 我认为您有一些选择,而您选择的决定应取决于您要承担的风险。 If it is financial data as you hinted, I think the decision should clearly be not doing any of this. 如果您如所暗示的那样是财务数据,我认为该决定显然应该不做任何事情。

One option is to store the 3rd party API password encrypted on your server with a key derived from the user's local password. 一种选择是使用从用户本地密码派生的密钥将加密的第三方API密码存储在服务器上。 As you don't store your user's local password, you can only decrypt the 3rd party API password upon user logon when you have his local one, and from there if you want to make future calls to the API impersonating the user, you will have to keep the plaintext version of the 3rd party password in server memory (the user's session). 由于您不存储用户的本地密码,因此只有在拥有用户本地密码时,才可以在用户登录时解密第三方API密码,并且如果您以后希望通过该调用来假冒该用户的API,就可以从那里解密将第三方密码的纯文本版本保留在服务器内存(用户会话)中。 I think that while in some applications this could probably be a viable option, for financial data this is unacceptable. 我认为,尽管在某些应用程序中这可能是一个可行的选择,但对于财务数据而言,这是不可接受的。

Another thing you could do is encrypt the 3rd party API password in Javascript as Dave Lasley described in his answer. 您可以做的另一件事是像Dave Lasley在他的回答中描述的那样用Javascript加密第三方API密码。 While that could work, it adds a lot of complexity, and as he also pointed out, implementation would be key. 尽管这可行,但会增加很多复杂性,正如他还指出的那样,实现将是关键。 It would be hard to get this right and maintain over time without introducing vulnerabilities. 如果不引入漏洞,很难做到这一点并随着时间的推移进行维护。 Also Javascript crypto has its problems, the best practice is to not do cryptography in Javascript. 同样,Javascript加密也有其问题,最佳实践是不要在Javascript中进行加密。 You would have to keep the 3rd party API password in Javascript memory, which is a very weak control, any single XSS would be able to steal it from there (any other browser store is even worse than a Javascript object in memory). 您必须将第3方API密码保留在Javascript内存中,这是一个非常弱的控件,任何单个XSS都可以从那里窃取它(任何其他浏览器存储都比内存中的Javascript对象更糟)。 Also the 3rd party API would need to support CORS from your domain (or * obviously). 同样,第三方API也需要支持您域中的CORS(或者显然是*)。

My take is that pretty much the only good way to do this would be a careful implementation with OAuth2. 我认为,执行此操作的唯一好方法是使用OAuth2进行仔细的实现。 If the API doesn't support that, then you should not do this at all unfortunately. 如果API不支持该功能,那么很遗憾,您不应该这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM