我正在一个网站上工作,该网站将允许用户使用来自Twitter,Google等的OAuth凭据登录。为此,我必须在这些提供商处注册并获得我拥有的超级秘密API密钥以誓言保护身体的各个部位。如果我的密钥被连接,则零件将被拉。

API密钥必须随我的源一起使用,因为它在运行时用于执行身份验证请求。就我而言,密钥必须存在于应用程序中的配置文件中或代码本身中。当我在一台计算机上进行构建和发布时,这不是问题。但是,当我们将源代码管理混为一谈时,事情就会变得更加复杂。

因为我是个贱人,所以我更喜欢在云或GitHub中使用免费的源代码控制服务,例如TFS。这给我留下了一个小难题:

当我的API密钥在我的代码中并且我的代码可在公共存储库中使用时,如何保持身体完整?

我可以想到许多方法来解决此问题,但是没有一个令人满意的方法。


我可以从代码中删除所有私有信息,并在部署后重新编辑。实施起来会很痛苦(我不会详细介绍很多方法),也不是一种选择。
我可以加密它。但是,由于我必须解密它,因此任何拥有源代码的人都可以弄清楚该怎么做。毫无意义。
我可以为私有源代码控制买单。哈哈j / k花钱了吗?请。
我可以使用语言功能将敏感信息与其他源代码隔离开,从而使它们不受源代码控制。这就是我现在正在做的,但是通过错误地检查机密文件很容易搞砸。

我确实在寻找一种有保证的方式,以确保我不会与世界共享我的私人信息(除了在手套上),这些信息将通过开发,调试和部署而平稳运行,并且也非常安全。这是完全不现实的。那我该怎么办呢?

技术细节:VS2012,C#4.5,源代码控制要么是TF服务,要么是GitHub。当前使用分部类将敏感键拆分到一个单独的.cs文件中,该文件不会添加到源代码管理中。我认为GitHub可能具有优势,因为.gitignore可以用于确保不检入部分类文件,但是我之前已经搞砸了。我希望有一个“哦,常见的问题,这就是你的做法”,但我可能不得不满足于“没有那么多的能力”,:/

评论

您可以确保保存您的API密钥的配置文件不在源代码控制的目录中,这将使它无法首先检入。

BitBucket.org有无限的私人存储库。自由。和gitHub仓库导入器(保留历史记录)

@Dainius我不信任我的开发人员,因为我认识他们。亲密地。实际上,我至少对自己很亲密……不,我会让那个人撒谎。但是我知道搞砸有多么容易,清理清理搞砸的历史将有多么困难。

@Dainius:是的。我查看团队代码中的每个字符。说真的我别无选择。我不能被蒙住眼睛。至少不可靠。但是我愿意,因为我是我的团队。我是TEAM中的I。有一个开发人员,就是我。我就是他是。如果他做得不对,我就是要搞砸这个人。我

您为什么首先要尝试将密钥编译到代码中?通常将此类内容放入配置文件中。

#1 楼

不要将您的秘密信息放入代码中。将其放入配置文件中,该文件在启动时会被您的代码读取。配置文件不应放在版本控制中,除非它们是“出厂默认设置”,否则它们不应具有任何私人信息。

另请参阅问题版本控制和个人配置文件以获取如何做到这一点。

评论


@RobertHarvey只是不将其放在版本控制上,而是在必要时添加了忽略规则。使用该软件的任何人都必须使用自己的API密钥来构建自己的配置文件。

– Philipp
13年7月21日在20:47

因此,当您构建和创建软件的发行版时,如何确定该软件随附配置文件?除非您有一些具有合理默认值的文件,否则通常不合理的期望您的用户经历制作配置文件的过程。

–托马斯·欧文斯♦
13年7月21日在21:13

好吧,出厂默认设置是其中一部分,“安装程序”或“首次运行向导”是另一部分

–约翰内斯
13年7月21日在21:56

如果许多用户有自己的安装,那么他们不应该创建和使用自己的API密钥吗?使用同一密钥的多个站点/安装可能不是一个好主意。如果只是一次安装,那么使用配置文件并不麻烦。

–麦克·韦勒
13年7月22日在11:53



@Will,如果由于实现细节的不切实际而无法执行此操作,那么我会说您只是没有适当的部署工具。使用未提交的机密配置文件进行部署应该完全轻松。由于我生活在Ruby生态系统而不是C#中,因此我无法为您提供具体建议。但是Ruby人们倾向于使用Capistrano进行自动部署。我确信C#也具有用于自动部署的工具,这将使过程变得容易。

–李本
13年7月22日在19:02

#2 楼

您可以将所有私有/受保护的密钥作为系统环境变量。您的配置文件将如下所示:

private.key=#{systemEnvironment['PRIVATE_KEY']}


这就是我们处理这些情况的方式,并且没有任何代码。与不同的属性文件和配置文件结合使用,效果很好。我们针对不同的环境使用不同的属性文件。在本地开发环境中,我们将开发密钥放在属性文件中以简化本地设置:

private.key=A_DEVELOPMENT_LONG_KEY


评论


如果我可以使其与托管选项一起使用,这将是一个合理的解决方案。不会是环境变量,但是某些键/值配置对在发布后不会被擦除...

–扯开了
13年7月22日在13:23

在将这些环境变量传送到实时环境之前,如何将它们放入构建服务器中?这样,您就可以准备生产资源/配置文件了。

– Ioannis Tzikas
13年7月22日在16:28



构建服务器是开发机器,这就是为什么我担心此信息可能会意外地检查到源代码管理的原因。

–扯开了
13年7月22日在17:01

这样的问题可能是服务器上的任何人都可以读取环境。

– JasonG
2014年4月20日的19:00

diogomonica.com/2017/03/27/…

–杰克逊
17年5月1日23:34

#3 楼

纯Git方式



.gitignore包含文件的私有数据
使用本地分支,其中将TEMPLATE替换为DATA

使用污迹/清洁过滤器,其中(本地)过滤器的脚本执行双向替换TEMPLATE <-> DATA


Mercury方法


MQ-patch( es)在伪代码之上,用TEMPLATE替换DATA(更改集是公共的,补丁是私有的)
关键字扩展带有特殊设计的关键字(仅在您的工作目录中扩展)

SCM-不可知的方式


在构建/部署过程中已替换了关键字


评论


嗯... git建议很好,您的不可知论建议给了我一个好主意...我可以使用构建事件将文件引入发布过程,然后再将其删除,从而有助于确保它不会被意外添加到源代码管理中。

–扯开了
13年7月22日在13:15

不,不,再一次-不!忽略文件对于添加一些非常特定的自定义来构建流程或其他东西是有好处的,但是永远不要将其用于存储任何安全数据。即使忽略安全数据,也不要将其存储在回购中。

– shabunc
13年7月23日在22:22



@shabunc-RTFM!忽略的文件未存储在仓库中

–懒Bad
13年7月24日在4:03

@LazyBadger-我很清楚它被忽略了。我也知道,在回购协议中,总有可能有人误会将其以某种方式添加到回购协议中。一些外部配置路径会更好。

– shabunc
13年7月24日在5:14

@shabunc-将配置保留在SCM路径之外的好地方。例如,这就是为什么Postgres允许您通过将密码放入文件中来绕过密码检查的原因。但是他们要求将密码文件放在〜/ .pgpass中-大概这不是很方便检查源代码控制的位置。他们知道,为了实现自动化,他们必须给您一把枪,但是他们会努力工作,以免您用它开枪射击。

–史蒂夫·米德利(Steve Midgley)
2013年12月9日23:31

#4 楼

我将机密放入加密的文件中,然后提交。系统启动时会提供密码,或者密码会存储在我不提交的小文件中。 Emacs将很乐意管理这些加密文件,这是很好的。例如,emacs初始化文件包括:(加载“ secrets.el.gpg”),该文件可以正常工作-启动编辑器时提示我输入那些罕见的密码。我不担心有人会破坏加密。

评论


这是一个很好的解决方案-很惊讶您没有更多的赞成票。我与一家处理学生数据的公司合作,该数据在美国受到联邦监管,因此他们在使用凭据和机密时必须格外小心。他们也是一家大公司,因此他们需要使用SCM来获取凭据,以便IT可以在构建工程师后找到/管理它们。您的解决方案正是他们所做的。他们有解密密钥文件,其中包含用于dev / staging / prod / etc的解密密钥(每个文件一个)。然后将所有机密加密并检入文件。解密文件用于在每个环境中获取它们。

–史蒂夫·米德利(Steve Midgley)
2013年12月9日23:36

好吧,从某种意义上说,加密机密(在这种情况下为API密钥)只会将问题从不提交机密数据转变为不提交密码短语(现在变成密码)。但是,当然,在系统启动时要求它是一个不错的选择。

– siegi
2014年4月27日在11:42

我喜欢这个解决方案。您提交的加密文件的类型可以是KeePass文件。它会为每个环境提供一个条目,使用notes字段存储.env文件的内容。几个月前,我写了一个可以读取keepass文件并使用条目的notes字段创建.env文件的工具。我正在考虑添加一个功能,以便可以在Node.js程序顶部执行require('switchenv')。env()并根据与NODE_ENV或类似内容匹配的条目创建process.env变量。 -> github.com/christiaanwesterbeek/switchenv

–克里斯蒂安·韦斯特贝克(Christiaan Westerbeek)
19年6月17日在20:32



#5 楼

这是非常特定于Android / Gradle的,但是您可以在位于gradle.properties的全局user home/.gradle/文件中定义密钥。这也很有用,因为您可以根据buildType或flavor使用不同的属性,例如,用于开发的API和用于发布的不同属性。

gradle.properties

MY_PRIVATE_API_KEY=12356abcefg


build.gradle

buildTypes {
        debug{
            buildConfigField("String", "GOOGLE_VERIFICATION_API_KEY", "\"" + MY_PRIVATE_API_KEY +"\"")
            minifyEnabled false
            applicationIdSuffix ".debug"
            }
        }


在代码中您会这​​样引用

String myAPI = BuildConfig.GOOGLE_VERIFICATION_API_KEY;


评论


BuildConfig会转换为相应的源文件,因此对apk进行简单的逆向工程将揭示您放入BuildConfig中的所有密钥和机密

– Dmitri Livotov
16 Mar 2 '16 at 9:39

的确是有道理的。但是问题是关于如何将api键保持在源代码而非二进制文件之外。

–scottyab
16 Mar 2 '16 at 9:58

#6 楼

您不希望将其与您的应用程序一起分发或存储在源代码存储库中。这个问题问的是如何执行此操作,而这通常不是正常操作。

移动Web应用程序

对于Android / iPhone,设备应从您的设备上请求KEY首次运行该应用程序时拥有自己的Web服务。然后将密钥存储在安全的位置。发布者是否应更改或撤消密钥。您的Web服务可以发布新密钥。

托管的Web应用程序

使用软件许可的客户在首次配置软件时必须手动输入密钥。您可以给每个人相同的密钥,也可以给他们不同的密钥。或者,他们可以拥有自己的密钥。

已发布的源代码

将源代码存储在公共存储库中,而不存储在KEY中。在文件的配置中,添加* place key here *行。当开发人员使用您的源代码时,他们会复制sample.cfg文件并添加自己的密钥。

您不要将config.cfg文件用于开发或生产。

评论


这个问题是问如何做到这一点,绝对没有。事实是这些密钥需要由代码使用,因此可以由代码访问,这通常意味着通过代码或配置文件,如果它们不在源代码中,则它们至少在附近,并且可能会意外地终止于资源。不幸的是,托管的Web应用程序是荒谬的。您无需通过您的(假设的)facebook帐户申请api密钥即可登录StackOverflow。如Q中所述,此处的place键是过度的简化,在dev-> pub环境中不起作用。

–扯开了
13年7月23日在19:33

我和其他许多人一样,已经正确回答了这个问题。您没有接受其中之一的事实意味着您不了解如何使用这些键。

–反应堆
13年7月23日在19:39

那么我们如何保护密钥发布Web服务呢?使用另一个键?

–张江格
2015年10月3日在16:44



同上@JianggeZhang所说的-这是危险的建议

– David K. Hess
16年6月6日在14:30

#7 楼

将环境变量用于每台服务器更改的秘密事物。

http://en.wikipedia.org/wiki/Environment_variable


如何使用它们取决于语言。

评论


对于许多人来说,建议不要采用模糊不清的安全性。您是否愿意详细说明您的答案?

–user53019
13年7月23日在19:32

这并不是很模糊,环境变量仅对您添加了它们的用户可用,因此所有凭据都对应用程序正在运行的用户上下文具有相同的保护。我更新了答案,以包括环境变量的概念。这更清楚吗?

–Filipe Giusti
13年7月25日在19:10



#8 楼

我认为这是每个人都在某个时候遇到麻烦的问题。

这是我使用的工作流程,可能对您有用。它使用.gitignore有点:


所有配置文件都放在一个特殊文件夹中(带有示例配置文件-可选)
所有配置文件都包含在.gitignore中,以便它们不会公开
在专用盒上设置gitolite服务器(或您喜欢的git服务器)
在专用服务器中添加包含所有配置文件的仓库
添加脚本要将配置文件复制到主存储库中的特殊文件夹(可选)中,现在您可以将配置存储库克隆到任何开发和部署系统。只需运行脚本将文件复制到正确的文件夹,就可以完成操作。

您仍然可以获得所有GitHub糖果,可以与世界共享您的代码,并且敏感数据永远不在主仓库中,因此它们不会公开。它们仍然只是任何部署系统的优势和复制品。

我为私人git服务器使用了15美元/年的价格,但您也可以根据Cheapskate的要求在家中安装一个;-)

PS:您也可以使用git子模块(http://git-scm.com/docs/git-submodule),但我总是忘记命令,因此规则又快又脏!

#9 楼

使用加密,但在启动时提供一个主密钥,作为控制台上的密码,仅在进程的用户可以读取的文件中,或从系统提供的密钥存储区(例如Mac OS密钥链或Windows密钥存储区)中提供。

要连续交付,您需要在某个位置记录各种密钥。应该从代码中区分配置,但是将其保持在版本控制之下是很有意义的。

#10 楼

3种尚未提及的策略(?)

在签入或在VCS中进行预签入挂钩


搜索具有高熵的字符串,例如- detect-secrets

regex搜索众所周知的API密钥模式。 AWS的AKIA *密钥就是一个示例,git-secrets是基于此的一种工具。此外,变量名称(例如带有固定分配的“密码”)。
搜索已知机密-您知道自己的机密,然后搜索文本。还是使用工具,我写了这个概念证明。

已经提到的策略


存储在源代码树之外的文件中
将其存储在源代码中树,但告诉VCS忽略它
环境变量是在源树之外存储数据的一种变体
只是不要向开发人员提供有价值的秘密


#11 楼

将私人信息置于您的源代码管理之外。创建一个未加载的默认分发版本,并使您的VCS忽略真实的默认版本。您的安装过程(无论是手动,配置/构建还是向导)应处理创建和填充新文件的过程。 (可选)修改文件的权限以确保只有所需的用户(Web服务器?)才能读取它。

好处:


不假定开发实体==生产实体
不假定所有协作者/代码审阅者都受信任
通过将其排除在版本控制之外来防止简单的错误
易于使用QA /内部版本的自定义配置自动进行安装

如果您已经在执行此操作,并且不小心将其检入,请将其添加到项目的.gitignore中。

周围有很多免费的Git主机,它们提供私有存储库。尽管您永远不应该对凭据进行版本控制,但是您可以便宜一些,也可以拥有私有存储库。 ^ _ ^

#12 楼

为何不将OAuth密钥作为原始数据存储在任何地方,为什么不通过某种加密算法运行字符串并将其存储为盐腌哈希呢?然后使用配置文件在运行时将其还原。这样,密钥就不会存储在任何地方,无论是存储在开发箱中还是服务器本身。

您甚至可以创建一个API,以便您的服务器根据每个请求自动生成一个新的加盐和哈希API密钥,这样您的团队甚至都无法看到OAuth源。

编辑:也许尝试斯坦福Javascript加密库,它允许进行一些相当安全的对称加密/解密。

评论


哈希通常是争夺的一种方式。但是,可以按照您的建议执行对称加密算法。

–user53019
13年7月23日在20:46

杜德(Dude),您无法(轻松)解密哈希。这就是哈希的全部要点。这是因为ME使用了其他人的API,他们在其中为ME分配了一个秘密密钥。我对它的散列确保(除非我每次选择一个较差的算法并将其破解),否则我无法使用其API。

–扯开了
13年7月23日在23:04