<p>存储身份验证凭据有两个非常不同的原因:</p>
<ol>
<li>要验证<em>您的</em>用户:例如,您只允许用户在验证您的程序之后访问服务</li>
<li>要使用另一个程序或服务验证程序:例如,用户启动程序,然后使用IMAP通过Internet访问用户的电子邮件。</li>
</ol>
<p>在第一种情况下,不应存储密码(或密码的加密版本)。相反,您应该使用高质量的salt来散列密码,并确保使用的散列算法在计算上非常昂贵(以防止字典攻击),例如PBKDF2或bcrypt。有关更多详细信息,请参见<a href="http://crackstation.net/hashing-security.htm">Salted Password Hashing - Doing it Right</a>。如果您采用这种方法,即使黑客检索盐渍的、慢散列的令牌,他们也不能用它做很多事情。</p>
<p>在第二种情况下,为了使秘密发现更加困难(正如您在问题中概述的那样),需要做很多事情,例如:</p>
<ul>
<li>在需要前对机密进行加密,按需解密,然后在需要后立即重新加密</li>
<li>使用地址空间随机化,因此每次应用程序运行时,密钥都存储在不同的地址</li>
<li>使用OS密钥库</li>
<L>使用“硬”语言,如C/C++,而不是基于VM的内省语言,如java或Python </LI>
</ul>
<p>这样的方法当然比什么都没有要好,但熟练的黑客迟早会把它破解的。</p>
<h2>代币</h2>
<p>从理论上讲,认证是证明被质疑者是他们所说的人的行为。传统上,这是通过共享的秘密(密码)来实现的,但也有其他方法来证明自己,包括:</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Out-of-band">Out-of-band</a>身份验证。例如,在我居住的地方,当我试图登录我的网银时,我在手机上收到一条<a href="http://en.wikipedia.org/wiki/One-time_password">one-time password</a>(OTP)短信。在这种方法中,我通过拥有一个特定的电话号码来证明我是</li>
<li><a href="http://en.wikipedia.org/wiki/Security_token">Security token</a>:要登录服务,我必须按令牌上的一个按钮以获取一个OTP,然后将其用作密码。</li>
<li><p>其他设备:</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Smart_card">SmartCard</a>,特别是美国国防部使用的,在那里它被称为<a href="http://en.wikipedia.org/wiki/Common_Access_Card">CAC</a>。Python有一个名为<a href="http://pyscard.sourceforge.net/">pyscard</a>的模块来接口这个</li>
<li><a href="http://en.wikipedia.org/wiki/Near_field_communication#Security_aspects">NFC</a>设备</li>
</ul></li>
</ul>
<p>以及更完整的列表<a href="http://en.wikipedia.org/wiki/Two-factor_authentication">here</a></p>
<p>所有这些方法的共同点是,最终用户控制这些设备,而这些秘密实际上永远不会离开令牌/卡/电话,当然也永远不会存储在您的程序中。这使他们更加安全。</p>
<h2>会话窃取</h2>
<p>然而(总是有一个然而):</p>
<p>假设您成功地保护了登录,这样黑客就无法访问安全令牌。现在,您的应用程序正愉快地与安全服务交互。不幸的是,如果黑客可以在您的计算机上运行任意可执行文件,那么黑客可以劫持您的会话,例如,在您有效使用服务时插入其他命令。换句话说,虽然你已经保护了密码,但它完全不相关,因为黑客仍然可以访问“安全的”资源。</p>
<p>这是一个非常真实的威胁,正如多个跨站点脚本攻击所显示的那样(一个例子是<a href="http://news.softpedia.com/news/U-S-Bank-and-Bank-of-America-Websites-Vulnerable-112148.shtml">U.S. Bank and Bank of America Websites Vulnerable</a>,但还有无数的例子)。</p>
<h2>安全代理</h2>
<p>如上所述,在第三方服务或系统上保留帐户凭据是一个基本问题,以便应用程序可以登录到该帐户,特别是在唯一的登录方法是用户名和密码的情况下。</p>
<p>一种通过将通信委托给安全代理来部分缓解这种情况的方法,并在应用程序和代理之间开发一种安全登录方法。在这种方法中</p>
<ul>
<li>应用程序使用PKI方案或双因素身份验证登录到安全代理</li>
<升i> 用户将安全凭据添加到安全代理的第三方系统。凭证从未存储在应用程序中</li>
<li>稍后,当应用程序需要访问第三方系统时,它会向代理发送请求。代理使用安全凭据登录并发出请求,将结果返回给应用程序。</li>
</ul>
<p>这种方法的缺点是:</p>
<ul>
<li>用户可能不希望信任具有凭据存储的安全代理</li>
<li>当数据通过安全代理流向第三方应用程序时,用户可能不信任该安全代理</li>
<li>应用程序所有者有额外的基础设施和托管成本来运行代理</li>
</ul>
<h2>一些答案</h2>
<p>所以,具体回答如下:</p>
<blockquote>
<p>How does one securely store authentication credentials using python? </p>
</blockquote>
<ul>
<li>如果为应用程序存储用于验证用户身份的密码,请使用PBKDF2算法,例如<a href="https://www.dlitz.net/software/python-pbkdf2/">https://www.dlitz.net/software/python-pbkdf2/</a></li>
<li>如果存储密码/安全令牌以访问其他服务,则没有绝对安全的方法。</li>
<li>但是,考虑使用<a href="http://pyscard.sourceforge.net/">pyscard</a>将身份验证策略切换到智能卡等。您可以使用智能卡对应用程序的用户进行身份验证,也可以使用X.509证书对应用程序的其他服务进行安全身份验证。</li>
</ul>
<blockquote>
<p>Can something be done about the language "everything is public" philosophy? I know "we're all consenting adults here", but should we be forced to choose between sharing our passwords with an attacker and using another language?</p>
</blockquote>
<p>IMHO在Python中编写一个<em>特定的</em>模块没有什么不对的,这样做最该死的是隐藏秘密信息,使它成为其他人重用的正确bug(烦扰其他程序员<em>是它的目的</em>)。你甚至可以用C编写大部分代码并链接到它。但是,出于明显的原因,不要为其他模块执行此操作。</p>
<p>不过,归根结底,如果黑客控制了电脑,电脑上根本就没有隐私。理论上最糟糕的情况是,你的程序运行在一个虚拟机上,黑客可以完全访问计算机上的所有内存,包括BIOS和图形卡,并且可以通过身份验证来逐步发现你的应用程序的秘密。</p>
<p>由于没有绝对的隐私,剩下的只是模糊化,而保护的级别只是模糊化的难度与熟练的黑客需要信息的程度之比。我们都知道如何<a href="http://news.cnet.com/8301-10805_3-57563484-75/windows-rt-jailbreak-tool-unleashed-online/">that ends</a>,即使是<a href="http://nakedsecurity.sophos.com/2012/10/25/sony-ps3-hacked-for-good-master-keys-revealed/">custom hardware</a>和<a href="http://www.ibtimes.com/ios-6-61-untethered-jailbreak-evasi0n-be-released-monday-algorithm-used-progress-bar-hints-12pm-est">billion-dollar products</a>。</p>
<blockquote>
<p>Using Python keyring</p>
</blockquote>
<p>虽然这将非常安全地管理与其他应用程序相关的密钥,但所有Python应用程序都可以共享对令牌的访问。对于你担心的那种攻击,这一点都不安全。</p>