Taken from our blog post on the subject:
https://blog.kolide.com/screensaver-security-on-macos-10-13-is-broken-a385726e2ae2

Since High Sierra this is the state of affairs related to the screensaver password:

  • There is no remote method (available from any vendor) to determine if the feature is turned on.
  • You have to be careful with you how craft a profile payload to enforce it.

This article will explain how we got here, and what you can do to mitigate this issue until Apple responds with a fix.

Querying the value set by the user

A common practice for the screensaver setting on macOS in enterprise environments is to enforce an acceptable maximum delay before the screen locks, but give the user permission to maintain a lower value if needed. For example, the policy might allow for 10 minutes of idle time before prompting for the password, but the user can keep the default value of 5 minutes, or even lower it to zero if they choose.

In order to enforce the 10 minute threshold, you would need to periodically query and reset the setting. The simplest way, is by running
defaults read com.apple.screensaver askForPassword to get the value, and then likely immediately followed by a defaults write command if the current value is above the threshold.

More advanced utilities use the CFPreferences API with python or Objective-C to read the value from the system. That’s exactly what Facebook’s Osquery agent does to populate the preferences table. Understanding the hierarchy of values in CFPreferences can be complex, but Osquery does a great job of abstracting that complexity away.

SELECT * FROM preferences WHERE domain="com.apple.screensaver" AND key="askForPassword" AND username="victor";

Using the above query you could run it with osqueryi to get the required values, or schedule it with osqueryd to periodically log the results of the query and send them to a centralized server. Based on the values being read by osquery, the server could then decide to enforce the acceptable 10 minute idle delay if the user was out of compliance.

Enforcing the preference with a Configuration Profile

With the introduction of Mobile Device Management (MDM), Apple provided Configuration Profiles as a method to enforce settings on macOS and iOS. While there are other options, Apple has strongly encouraged profiles delivered through MDM as the configuration distribution mechanism.

To manage the screensaver preference with a profile, we have to craft an XML payload that looks roughly like this:

<dict>
    <key>PayloadDisplayName</key>
    <string>Security and Privacy</string>
    <key>PayloadEnabled</key>
    <true/>
    <key>PayloadIdentifier</key>
    <string>com.acme.config.screensaver</string>
    <key>PayloadUUID</key>
    <string>966eb7be-81bd-f8cc-f3e3-078d93f1b4a4</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>PayloadType</key>
    <string>com.apple.screensaver</string>
    <key>askForPassword</key>
    <true/>
</dict>

Though this XML is verbose, the important takeaway is that it manages the com.apple.screensaver preference domain using a key identical to the one enforced by CFPreferences (typically, Apple uses the CFPreferences API to read and write configuration values.).

It is important to note when querying profiles that osquery uses a different table to query enforced configuration (managed_policies) than user defined configuration (preferences). So if you’re an osquery user querying macs, you usually have to run two or more queries to get an accurate state for preferences:

  1. Query the managed_policies table for the domain and key you’re interested in. If the key exists, that is the enforced value on the system, and therefore the effective value. If you get 0 results from the host, it means the value is not enforced, but it still might be set.
  2. Query the preferences table, adding the user whose preferences you’re looking for as a JOIN column. If the user sets a value other than the system default, it will be returned here.

Changes to the Screensaver Profile in 10.13

With the rollout of High Sierra across our fleet, it became obvious that osquery was failing to read the screensaver values correctly. At first we were concerned this was a regression in osquery. Querying CFPreferences through defaults read helped us determine that was not the case. No data seems to be available through any API.

While trying to figure out how to query for the configuration, we ran into an inexplicable problem: Somehow we got the computer in a state where the profile was on the system and CFPreferences told us the askForPasswordkey was enforced, but the screensaver wouldn’t actually come on and the checkbox in the System Preferences security tab remained unchecked.

The Security & Privacy section of System Preferences shows a disabled checkbox when this setting is managed.

So our profile was not enforced, and the screensaver lock was completely disabled, although osquery and any other tool we tried told us that the value was enforced. This was so odd that I created a new VM to test further. After going through the same steps and resetting the VM, I confirmed what I already suspected: The profile is broken. I now had enough to file a bug report. The profile does work sometimes, so depending on your workflow you may or may not experience this issue.

If the profile is installed immediately during device bootstrap, the profile enforces the defined setting and the screensaver lock works as expected.

But, if the user has a chance to set their own preference before the profile is applied, the profile has no effect at all. Installing the profile does not override the user’s configuration, but it does lock them out of the ability to change it for themselves.

Adding the askForPasswordDelay key to the profile helps to remediate the profile, but only slightly. The actual preference only appears to be synced after the user logs in again.

We’ve seen this situation before. As recently as the release of macOS 10.12 (Sierra) the HomePage key in com.apple.Safari became impossible to query. Apple had moved the homepage preference to the Local Items keychain so defaults read was no longer able to access it. I reached out to Michael Lynn, a fellow Mac admin whose done a lot of work exploring various system APIs and has valuable insights into troubleshooting macOS system APIs. Michael suggested I log out of the current user, and using another admin account, delete the current user’s Local Items keychain.

After following Michael’s advice and deleting the affected user’s keychain, I logged back in as that user and noted that my broken profile was fixed and enforcing the expected behavior. Great!

The bad news is that while we solved the mystery of how this value is stored, deleting the user’s local keychain is not a viable solution or workaround.

Conclusions

Taking a step back, this situation is just a symptom of the massive upheaval and changes to the security architecture of macOS and Mac devices.

This is a good thing, and while Apple should be applauded for attempting to innovate the security model of macOS, users and organizations can only benefit if it’s done in a responsible manner.

Apple clearly has a plan for how to manage Macs and macOS fleets and that plan definitely includes heavy reliance on MDM. Unfortunately, the intent of their decisions is confusing when they move settings to the keychain where tools like osquery can no longer inspect their values but simultaneously introduce bugs that prevent the management and inspection of that same setting via the MDM API.

While this situation in isolation isn’t damning, this is just another datapoint in a recent pattern of behavior. For example:

  • Apple pushed forward User Approved Kernel Extensions, without a way for enterprises to configure a whitelist (hopefully fixed in 10.13.2)
  • A rewrite of Disk Utility introduced a security flaw in the password hint mechanism.

Going forward, Apple’s constant iteration on security mechanisms introduces risks to operators, but tools like osquery can help us remain vigilant and identify these issues earlier.

Recommendations

Until Apple resolves this bug, screensaver security/lock settings must be managed carefully. More specifically:

  1. Enforce the profile ASAP, during initial bootstrap.
  2. Make sure the askForPasswordDelay key is used in the profile.

If you’re affected by this or similar changes, I recommend Michael Lynn’s talk from MacDevOpsYVR earlier this year.

Did this answer your question?