swift package_Swift Package Manager有潜在的安全风险

本文关注Swift Package Manager可能存在的安全问题,探讨了其潜在的风险,来源于对原文的翻译。
摘要由CSDN通过智能技术生成

swift package

Let me start off by saying I absolutely love Swift Package Manager and I think it’s the future of dependency management on iOS, so-much-so I’ve written posts on what we can do with it.

首先,我要说我绝对喜欢Swift Package Manager,并且我认为这是iOS上依赖管理的未来,所以我写了一些关于如何使用它的文章

But I also want to use this opportunity to highlight a potential risk with using it that I became aware of today. I initially thought there was no issue tracker for Swift Package Manager since there isn’t one in the GitHub repo, but I’ve since reported this issue on the Swift bug tracking Jira instance (SR-13346).

但是我也想利用这次机会来强调我今天意识到的使用它的潜在风险。 我最初以为Swift Package Manager没有问题跟踪程序,因为GitHub存储库中没有该问题跟踪程序,但此后我在Swift Bug跟踪Jira实例( SR-13346 )上报告了此问题。

I’ve found a way to run any code I want when you use one of my Swift packages (providing you don’t check the Package.swift file before hand), and it’s a lot simpler than you might think. Let me show you how.

当您使用我的Swift软件包之一(前提是您事先不检查Package.swift文件)时,我找到了一种运行所需代码的方法,它比您想象的简单得多。 让我告诉你怎么做。

骇客 (The hack)

It’s a very, very simple hack, making use of anonymous closures to lazily load the Package instance defined in the Package.swift file for a package.

这是一个非常非常简单的技巧,它利用匿名闭包来延迟加载Package.swift文件中定义的Package实例。

UPDATE: After writing this post and filing a bug with the Swift team I realised even this is more complicated that it needs to be. You can simply create a function that returns anything that the Package instance needs (like a string for the name) and execute any other code you want before returning.

更新:写完这篇文章并向Swift团队提交了一个错误之后,我意识到,这甚至更复杂了。 您可以简单地创建一个函数,该函数返回Package实例所需的任何内容(例如名称字符串),并在返回之前执行所需的任何其他代码。

First, let’s look at a normal, simple Package.swift file that gets generated when you run swift package generate:

首先,让我们看一个普通的,简单的Package.swift文件,该文件在您运行swift package generate

When you add this package as a dependency, Swift Package Manager does some magic by looking for the package instance in this file.

当您将此软件包添加为依赖项时,Swift软件包管理器通过在此文件中查找package实例来做一些魔术。

Since this file is just a regular Swift file, we can write any Swift code we want in here, including tricking Swift Package Manager to call a function whenever the package instance is referenced:

由于此文件只是常规的Swift文件,因此我们可以在此处编写任何所需的Swift代码,包括诱骗Swift包管理器在引用package实例时调用函数:

Image for post

The code above has hardly been changed, but can now be used to run any code we want in doSomething(). Let’s add some code to doSomething that makes your Mac speak out loud (yes really!):

上面的代码几乎没有更改,但是现在可以用于运行doSomething()我们想要的任何代码 。 让我们添加一些代码到doSomething ,使您的Mac大声说出来(是的!):

Image for post

In the above code, we’ve updated doSomething so it now runs an executable file called say which speaks out any words you give it as an argument (included in every Mac by default).

在上面的代码中,我们更新了doSomething因此它现在运行一个名为say的可执行文件,该文件say您作为参数输入的所有单词(默认情况下包括在所有Mac中)。

Notice how we’re able to literally execute a programme that is stored in usr/bin. To do this we have to use a Process instance, which is part of AppKit, which we have no problems importing into our Package.swift file, because it’s just Swift code running on a Mac.

注意我们如何能够从字面上执行存储在usr/bin 。 为此,我们必须使用Process实例,该实例是AppKit一部分,我们可以AppKit其导入Package.swift文件,因为它只是在Mac上运行的Swift代码。

If you add our package as a dependency to another package, or as a dependency in an Xcode project, you’ll hear your Mac say “hello world” whenever the package is resolved. In fact, you only have to save the Package.swift file to test it and it’ll speak.

如果将我们的软件包作为依赖项添加到另一个软件包,或者作为Xcode项目中的依赖项添加,则只要解决该软件包,您都会听到Mac发出“ hello world”的声音。 实际上,您只需要保存Package.swift文件即可对其进行测试,它将开始说话。

This gets more worrying when you add this package as a remote dependency in Xcode (11 or 12), because the code runs as soon as you add it as a dependency:

当您将此程序包添加为Xcode(11或12)中的远程依赖项时,这会更加令人担忧,因为一旦将其添加为依赖项,代码就会立即运行:

Image for post

By the time you get to that screenshot above in Xcode 11 or 12, the function has already been called and your Mac has said “hello world” out loud.

当您到达上面Xcode 11或12中的屏幕快照时,该功能已经被调用,并且您的Mac已经大声说出“ hello world”。

更进一步 (Going further)

Just being able to import AppKit opens up the possibility of so many things, both malicious and not. As an example, with AppKit you can get a list of running apps, terminate them and launch new processes with NSWorkspace.

仅仅能够导入AppKit就打开了很多东西的可能性,无论是恶意的还是非恶意的。 例如,使用AppKit可以获取正在运行的应用程序列表,将其终止并使用NSWorkspace启动新进程。

We can import other macOS frameworks too, like Collaboration, which lets us get information like the full name of the current user, and more alarmingly, test to see if a password is the correct password:

我们也可以导入其他macOS框架,例如Collaboration ,它可以让我们获取当前用户的全名之类的信息,更令人震惊的是, 测试一下密码是否为正确的密码

Image for post

If “notmypassword” happens to be your actual login password for your Mac, the above code will speak out:

如果“ notmypassword”恰好是您Mac的实际登录密码,则上面的代码将说明:

“Hello [your name], notmypassword is your password”

“您好[您的名字],notmypassword是您的密码”

Even without importing AppKit or any of the other macOS frameworks, we can import Foundation which allows us to make any network requests we want:

即使不导入AppKit或任何其他macOS框架,我们也可以导入Foundation,它使我们能够发出我们想要的任何网络请求:

Image for post

The above code uses a DispatchGroup to make the thread wait until the network call has completed. This network call could be used to download any data from any site, and upload any data anywhere.

上面的代码使用DispatchGroup使线程等待,直到网络调用完成。 该网络呼叫可用于从任何站点下载任何数据,以及在任何地方上传任何数据。

If that wasn’t enough, since you can access FileManager from Foundation, you can also write any data to disk, as well as read directly from the filesystem, or delete files. In theory, you could delete the entire user directory (although I was too chicken to try!).

如果这还不够,由于可以从Foundation访问FileManager ,因此还可以将任何数据写入磁盘,以及直接从文件系统读取或删除文件。 从理论上讲,您可以删除整个用户目录(尽管我实在无法尝试!)。

Image for post

The above code iterates through the entire filesystem, logging each item to the console. Thankfully in Catalina you do have to give Xcode permission to access some directories, but that just confirms that you’ll be able to run code in any privileged way that Xcode does. I’m also subconciously trained to just accept any permissions requests that Xcode throws up at me.

上面的代码遍历整个文件系统,将每个项目记录到控制台。 幸运的是,在Catalina中,您确实必须授予Xcode访问某些目录的权限,但这只是确认您将能够以Xcode可以使用的任何特权方式运行代码。 我还接受过潜意识的培训,可以接受Xcode向我提出的所有权限请求。

These are just a few examples off the top of my head of what we can do with this, I’m sure there are plenty more that cleverer people can think of.

这些只是我们可以采取的措施之外的一些示例,我敢肯定,聪明人可以想到的还有很多。

缓解措施 (Mitigations)

What can you do to protect yourself from people who want to abuse this vulnerability?

您可以采取什么措施来保护自己免受想要滥用此漏洞的人的侵害?

Well, unfortunately you can’t entirely, but you can help protect yourself by checking each 3rd party Package.swift file before using it, and make sure you target a specific version in a remote repo rather than always resolving the latest version of a branch. Remember though there’s nothing stopping someone from changing the code that a tag in a remote repo references.

好吧,很遗憾,您不能完全解决问题,但是您可以通过在使用前检查每个第3方Package.swift文件来保护自己,并确保在远程存储库中定位特定版本,而不是始终解析分支的最新版本。 。 请记住,虽然没有什么可以阻止某人更改远程仓库中标签所引用的代码。

Additionally, you should only use packages from developers you trust. Unfortunately this could be an unfair disadvantage for new developers with something cool they want to share via Swift Package Manager, and in any case there’s still a risk (albeit small) reputable developers could have their repositories compromised.

此外,您应仅使用您信任的开发人员提供的软件包。 不幸的是,这对于希望通过Swift Package Manager分享一些很棒的东西的新开发者来说可能是一个不公平的劣势,并且无论如何,声誉良好的开发者(尽管很小)都可能会损害其存储库。

Hopefully, GitHub will be able to add some vulnerability checks for Swift packages like they do with other language dependencies in the future, and of course hopefully the Swift developers find a way to plug this properly without impacting the usefulness of either Swift Package Manager or system frameworks.

希望GitHub能够像将来与其他语言依赖项一样为Swift软件包添加一些漏洞检查,当然希望Swift开发人员找到一种正确插入此漏洞的方法,而不会影响Swift Package Manager或系统的实用性构架。

In the interests of fairness, I should also point out that Cocoapods has a way of running scripts as the framework is being built, however they at least choose to log warnings to developers so it’s not completely silent. And they expose it as an official feature so people are more aware of it.

为了公平起见,我还应该指出, Cocoapods在构建框架时有一种运行脚本的方法 ,但是它们至少选择将警告记录到开发人员,因此它并不是完全安静的。 并且他们将其公开为官方功能,因此人们对此有所了解。

You should also make sure you’re not storing anything sensitive on disk outside of the Keychain, that means no storing passwords in unencrypted text files, no leaving private keys or certificates on the desktop etc.

您还应该确保不在钥匙串之外的磁盘上存储任何敏感内容,这意味着不要在未加密的文本文件中存储密码,也不要在桌面上保留私钥或证书等。

Additionally, although I was able to write code that retrieves private keys from the keychain (or references to keys, more specifically), I wasn’t able to actually use the key to sign data without a permissions prompt coming up:

此外,尽管我能够编写从钥匙串(或更具体地讲,对钥匙的引用)中检索私钥的代码,但在没有出现权限提示的情况下,我无法实际使用该钥匙对数据进行签名:

Image for post

This is why it’s important not to blindly allow permissions for things that pop up, even if they seem like they’re coming from the system. For example, using some keychain code I was able to get this popup to appear while trying to use private keys:

这就是为什么重要的是,不要盲目地允许弹出的权限,即使它们看起来好像来自系统。 例如,使用一些钥匙串代码,我能够在尝试使用私钥时显示此弹出窗口:

Image for post

That one is particularly worrying because it doesn’t mention my package name anywhere, and since it’s saying macOS wants to make changes I would be tempted to allow it if I didn’t know it was my code that caused it. I don’t know what entering my username and password does in this case, because again I was too chicken to try (maybe I can set up a demo machine so I can properly try this stuff without worrying!).

那个特别令人担忧,因为它在任何地方都没有提及我的软件包名称,并且因为它说macOS想要进行更改,如果我不知道是由我的代码引起的,我很想允许它。 在这种情况下,我不知道输入用户名和密码会做什么,因为我再也不想尝试了(也许我可以设置一个演示机,这样我就可以不用担心而正确地尝试这些东西了!)。

并不全是坏事 (It’s not all bad)

If you’ve read this far you might be worried (and rightly so), but it’s also worth pointing out that although this can be used for evil, it can also be used for good.

如果您已经读了那么多的书,您可能会担心(正确的说),但是也值得指出的是,尽管这可以用于邪恶,但也可以用于善事。

This sort of thing could enable code generation (which is why I thought of this in the first place), or providing some required automatic setup for users of libraries that have a difficult setup process (like adding build phase scripts for Firebase).

这类事情可以启用代码生成(这就是我首先想到的原因),或者为安装过程较困难的库用户提供一些必需的自动设置(例如为Firebase添加构建阶段脚本)。

Sadly, we live in a world where bad actors ruin things and That’s Why We Can’t Have Nice Things™️.

可悲的是,我们生活在一个坏演员毁掉事物的世界,这就是为什么我们不能拥有Nice Things™️。

Swift团队该如何解决? (How can the Swift team fix it?)

I’m honestly not sure the best way for the team to fix it, if Swift code is going to be allowed in full then this will always happen. Perhaps disallowing imports or functions when parsing the Package.swift file could work.

老实说,我不确定团队修复的最佳方法,如果要完全允许使用Swift代码,那么这种情况总是会发生。 可能在解析Package.swift文件时禁止导入或函数可能起作用。

I’ve created an example repository which you can check out if you want to see it for real.

我创建了一个示例存储库 ,您可以查看该存储库是否是真实的。

翻译自: https://medium.com/@KaneCheshire/swift-package-manager-is-a-security-risk-4d13f3a7bc3b

swift package

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值