Skip to content

3. App Sandbox and Entitlements

sethlu edited this page Mar 2, 2016 · 5 revisions

All apps that are submitted for distribution inside the Mac App Store must run inside a "sandbox." This basically means that every sandboxed apps will run under a limited set of permissions, and damages from malicious code, if any, could be minimized. If your application requires additional capabilities, it then must include in its entitlements the corresponding entitlement keys, which are specified during the code signing process. The entitlement keys mark capabilities and/or permissions that are needed by the application.

Note: The App Sandbox basically means code-signing your app with entitlements, and specifically the sandbox entitlement key enabled.

A list of App Sandbox entitlement keys and their definitions can be found on Apple Developer. You may notice that a sandbox app does not have full-access to every aspect of the machine. For example you cannot read/write to any location on the machine; your app is limited to specific folders such as Downloads, Music, Pictures, etc. So additionally, there are temporary exception entitlement keys available that allow your apps to perform certain operations otherwise disallowed by the App Sandbox, and to access files outside of these areas in this case. Temporary exceptions come with their own requirements, for example the user must specifically select a location with an Open File dialog. Your app may then have temporary permission to that location.

Entitlements are specified using a .entitlements file with format like property list (.plist) or XML. You must provide an entitlement file for the application bundle itself and a child entitlement file which basically describes an inheritance of properties, specified for all other enclosing executable files like binaries, frameworks (.framework), and dynamically linked libraries (.dylib).

Note: It's worth mentioning that wildcard expressions with asterisks are generally not accepted by codesign. Also, the entitlement files have size limits. So it's not at all recommended to throw in every possible cases, populating the file to several megabytes, which will throw errors when code-signing. Keep it as brief as possible.

Extend the Entitlements

With electron-osx-sign, it is unnecessary to manually prepare those entitlement files unless for specific purposes. The entitlements for signing the application bundle by default are defined in mas.default.entitlements; and for the enclosing executable files, in mas.inherit.default.entitlements.

Below is mas.default.entitlements. The easiest way to add entitlements is to edit a copy and to simply customize the plist by adding your additional entitlements.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
  </dict>
</plist>

Below is mas.inherit.default.entitlements. You can generally leave this file as-is because all of the enclosing files will inherit whatever entitlements that are specified in the entitlements for the application bundle, mas.default.entitlements. (This is done with the key com.apple.security.inherit set to true.)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.inherit</key>
    <true/>
  </dict>
</plist>
Customize Entitlements

The following example is a plist for an app that will read from/write to the "Downloads" folder as well as make network requests to external servers. Notice that it simply provides an additional "key" for each of these capabilities. For example, com.apple.security.files.downloads.read-write specifies permission to read/write to the user's downloads folder and com.apple.security.network.client specifies permission to make network requests.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.network.client</key>
    <true/>
  	<key>com.apple.security.files.downloads.read-write</key>
  	<true/>
  </dict>
</plist>

Please also make note that some entitlement keys may require value type array, instead of boolean values. For example, com.apple.security.temporary-exception.files.absolute-path.read-write, which enables read/write access to the specified files or directories at specified absolute paths, should be done as follows if to access any directories. This act is not recommended as we should minimize what the sandboxed apps touch in the system, and may probably result in rejection from submission.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
    <array>
      <string>/</string>
    </array>
  </dict>
</plist>

Note: You can always append more than just one <string> within the <array> container.

What A Sandboxed App Could Access Anyway

Though sandboxed, the apps can touch some parts of the system without specifying additional entitlements. They could read files that are world readable, in certain directories, including the following:

  • /bin
  • /sbin
  • /usr/bin
  • /usr/lib
  • /usr/sbin
  • /usr/share
  • /System

Also, they could read/write files in directories created or granted for temporary use.

TODO: Expand more on this part relating to NSOpenPanel and recent issues from electron-packager.

Apply the Entitlements

If you have any custom entitlements, please specify entitlements and/or entitlements-inherit when code-signing with electron-osx-sign. On the other hand, if you are using electron-packager and would like to sign with entitlements directly from it, the sign-entitlements option is also available for use.

# EITHER pack your app and sign it both at once
electron-packager . "My App" --platform=mas --arch=x64 --version=0.35.6 --app-bundle-id="com.mysite.myapp" --app-version="1.0.0" --build-version="1.0.100" --sign --sign-entitlements="path/to/parent.entitlements" --sign-entitlements-inherit="path/to/child.entitlements"

# OR pack your app first then manually sign it
electron-packager . "My App" --platform=mas --arch=x64 --version=0.35.6 --app-bundle-id="com.mysite.myapp" --app-version="1.0.0" --build-version="1.0.100"
# Code-sign app bundle with custom entitlements
electron-osx-sign "My App-mas-x64/My App.app" --entitlements="path/to/parent.entitlements" --entitlements-inherit="path/to/child.entitlements"

Note: electron-osx-sign will take care of all enclosing executables under My App.app/Contents/Frameworks. If there are other binaries that do not come with Electron under My App.app/Contents/Resources that you would like to be signed as well, provide them in additional-binaries.