Mac终端安全:如何阻止用户删除钥匙串项?
Hey there! You’re already doing a great job using ES_EVENT_TYPE_AUTH_UNLINK to block app file deletions—extending this to protect keychain items just requires targeting the right Endpoint Security (ES) event type and adding some targeted logic to your handler. Here’s how to pull it off:
1. Target the Correct ES Event Type
Keychain deletion operations are surfaced via the ES_EVENT_TYPE_AUTH_KEYCHAIN_DELETE event. This is the authorization event you’ll need to subscribe to, alongside your existing ES_EVENT_TYPE_AUTH_UNLINK event.
2. Update Your Event Subscription
When initializing your ES client, add ES_EVENT_TYPE_AUTH_KEYCHAIN_DELETE to your list of subscribed events. For example (in Objective-C):
// Define the events you want to monitor es_event_type_t monitoredEvents[] = { ES_EVENT_TYPE_AUTH_UNLINK, ES_EVENT_TYPE_AUTH_KEYCHAIN_DELETE }; es_client_t *esClient; es_new_client_result_t clientResult = es_new_client( &esClient, yourEventHandler, // Your existing event handler function NULL, // Context pointer (if needed) 0, // Flags monitoredEvents, sizeof(monitoredEvents) / sizeof(monitoredEvents[0]) ); if (clientResult != ES_NEW_CLIENT_RESULT_SUCCESS) { // Handle initialization failure (log errors, exit gracefully) }
3. Add Logic to Block Targeted Keychain Items
In your event handler, add a case for ES_EVENT_TYPE_AUTH_KEYCHAIN_DELETE. You’ll extract keychain item attributes (like service name, account, or access group) to identify items belonging to your app, then deny the deletion request if it matches your criteria.
Here’s a sample handler snippet:
void yourEventHandler(es_client_t *client, const es_event_t *event) { switch (event->event_type) { case ES_EVENT_TYPE_AUTH_UNLINK: // Your existing file deletion blocking logic here es_respond_auth_result(client, event, ES_AUTH_RESULT_ALLOW); // Or DENY as needed break; case ES_EVENT_TYPE_AUTH_KEYCHAIN_DELETE: const es_event_keychain_delete_t *keychainEvent = es_event_get_keychain_delete(event); // Extract keychain item attributes to verify ownership const char *targetService = es_string_copy_cstring(es_event_keychain_delete_get_service(keychainEvent)); const char *targetAccessGroup = es_string_copy_cstring(es_event_keychain_delete_get_access_group(keychainEvent)); // Check if the item belongs to your app (customize this check!) bool shouldBlock = false; if (targetService != NULL && strcmp(targetService, "com.yourcompany.yourapp.keychain-service") == 0) { shouldBlock = true; } else if (targetAccessGroup != NULL && strcmp(targetAccessGroup, "com.yourcompany.yourapp.access-group") == 0) { shouldBlock = true; } // Respond to the event es_respond_auth_result(client, event, shouldBlock ? ES_AUTH_RESULT_DENY : ES_AUTH_RESULT_ALLOW); // Clean up allocated strings if (targetService) free((void *)targetService); if (targetAccessGroup) free((void *)targetAccessGroup); break; default: // Allow all other unhandled events es_respond_auth_result(client, event, ES_AUTH_RESULT_ALLOW); break; } }
4. Critical Notes for Success
- Entitlements & Signing: Ensure your ES extension has the
com.apple.security.endpoint-security.cliententitlement in its.entitlementsfile, and that it’s properly signed with a valid Apple Developer certificate. - User Authorization: Endpoint Security extensions require user approval via System Settings > Privacy & Security > Security Extensions. You’ll need to prompt users to grant this permission on first run.
- Precision Matching: Avoid over-blocking by using specific attributes (like your app’s service name or access group) to target only your app’s keychain items—don’t block all keychain deletions, as this can break system or other app functionality.
- Memory Management: Remember to free any strings copied via
es_string_copy_cstringto avoid leaks.
内容的提问来源于stack exchange,提问作者Durgaprasad

