Most GitFinder users seem to be reasonably technical, which should not come as a surprise, given the fact they use git version control system on a regular basis. Hence, many of them have noticed GitFinder being sandboxed application. Quite a few asked for reasons for such design decision, or commented on whether that decision was right or wrong one. Instead of responding to each such question and comment separately, I decided to address them all with a dedicated blog post. I will also use this opportunity to give my opinion about application sandboxing on macOS.
Apple introduced application sandboxing with macOS 10.7 (also known as Lion) back in spring of 2011. It was promptly met with mixed feelings by macOS developers community, and reactions were mostly negative. There were two major reasons for such reactions. Firstly, sandboxing puts quite some restrictions on what an application can do out of the box. Most of those restrictions could be overcome or worked around, but that requires significantly different and arguably more complicated approach to application design and development than previously was the case. Even then, some of the restrictions could never be overcome, due to what sandboxing is primarily made for. However, developers were not required to sandbox their applications, non-sandboxed applications were running perfectly fine, just like before. But then we come to the second reason and that was Apple’s decision to require sandboxing for all applications offered in the Mac Apple Store (MAS). The first deadline for this requirement was set to November 1 of 2011. Due to laud negative reactions and many requests for extension, the deadline was later moved to March 1 of 2012. Such loud reactions were understandable, since many developers owning complicated applications required more time to redesign them for sandboxing. Some have never managed to achieve this goal though, and have left MAS.
This MAS requirement have caused a lot of fear among both developers and users that eventually, within the next two or three iterations of the major OS version, Apple would start requiring all (not only MAS) applications to be sandboxed in order to run on the OS. Some people have been very convinced and vocal about this, even though many developers have commented that such move would probably not happen, as that would eventually completely kill the platform, since some popular and powerful application would never be able to fulfil all sandboxing requirements. Luckily (and I would also say, expectedly), in almost seven years since mandatory sandboxing for MAS applications has been introduced, Apple has never shown any intention to require all applications to be sandboxed. Developers not being able to fulfil sandboxing requirements continued happily selling their applications outside of MAS, just like they have been doing for years (and some for decades). Many of them abandoned MAS later, but for completely different reasons (this might change with MAS revamp, expected with the release of macOS 10.14 Mojave, but that is another story). It seems all sandboxing affairs and noise haven’t badly affected macOS applications ecosystem as it was initially expected.
Besides sandboxing (and many other things), Lion also introduced XPC services API. That was yet another Apple’s take on interprocess communication and remote procedure calling. Armed with previous experience with other APIs already available in macOS for same or similar purposes (DOs, NSTask, POSIX fork, RPC…), with XPC Apple mostly got it right from the very beginning. The main goal of XPC services is splitting an application into parts responsible for various critical or processing intensive tasks and then execute those tasks in completely separated processes (services), embedded into the main application bundle. If any of the tasks fails or crashes, it will not cause the whole application to crash as well. The beauty of XPC API is, among others, elegant communication between services and hosting application and means of seamlessly recovering in case a service fails or crashes.
Even though sandboxing is not the primary focus of XPC API, it actually helps with it a lot. The basic idea is to distribute application tasks among different XPC services, not only considering the nature of the tasks, but also in a way that every service should have the minimal set of required sandboxing entitlements, sufficient to do the job. That way, if the application gets securely compromised, an attacker would not be able to do much damage, since all important sandboxing entitlements are given to XPC services, with the application being “only” a UI wrapper and communication mediator between them. Similarly, if an XPC service gets compromised, it should have only the minimal set of necessary entitlements, thus minimising the damage the attacker can cause.
I’ll try to illustrate this concept on GitFinder’s example. GitFinder has AvatarService XPC service, responsible for querying your contacts (if you give it permission) and finding appropriate photos matching email addresses, so that they can be displayed in the commits list in the main application. The only entitlement this service has is to access your Contacts (previously known as Address Book). If this service gets securely compromised by some malware and an attacker gains an access to all of your contacts, no particular damage can be done, since AvatarService cannot read from disk nor write to it, nor can it access network and possibly transfer contacts list to some remote location. Similarly, NetworkService XPC service in GitFinder has the sole entitlement to access the network, so even if it gets compromised the attacker cannot read anything from disk nor write to it.
This sandbox + XPC services combo made me an instant lover and adopter of application sandboxing. I really like the idea of splitting application into different processes, each doing its own thing and that thing only. It reminds me of the UNIX philosophy, summarised by Peter H. Salus in 1994 as: “write programs that do one thing and do it well”. Combined with sandboxing and giving each service only the minimal set of necessary entitlements, this combination provides really powerful toolset for crating rich and powerful, yet more secure applications. Apple has been accused for a very long time for not doing anything regarding security of macOS and applications running on it and that the only security “measure” they were relying on was “security through obscurity” (meaning smaller adoption of macOS compared to Windows made it not-so-desirable target for attacks). I find it a bit unfortunate that, once Apple guys finally started doing something meaningful in that regard, their efforts were met with such harsh criticism by the developers community. Some of that criticism was justifiable and during the past seven years Apple has done a lot to fix and improve initial shortcomings of sandboxing. Many things, impossible to achieve with sandboxed applications in the very beginning, can now be easily implemented following still rather strict sandboxing rules.
The way I see it, some 80-85% of macOS applications can be sandboxed, without sacrificing any functionality or user experience. I believe GitFinder is a very nice proof of this claim; it’s a full-featured and functional git client, yet completely sandboxed. My intention is to keep it that way, as long as it is possible, hopefully forever (well, at least while it is under active development :-)). However, I realise making sandboxed applications is more demanding than making their non-sandboxed counterparts. I also realise some applications will never be sandboxed, that would simply be impossible. Yet, that fact should not diminish all the good things sandboxing brings and goals it achieves.