Layered phishing protection on iOS: content blockers, SMS filtering, and the VPN question
A user gets an SMS from a number they don't recognize. The message says their package is held at customs and links to a shortened URL. They tap it. Safari opens. The page looks legitimate enough, asks for a card to "release the parcel," and the next day the card is being used in another country.
This sequence has at least three points where iOS could have intervened: the SMS itself, the link Safari was asked to open, and the page Safari rendered. Apple provides a targeted extension point for the first two and partial coverage of the third. Outside Safari there is no built-in content-filtering extension point at all. A link opened in Messenger, in a social app's in-app browser, or in an email client's `WKWebView` is invisible to the two extensions this post covers. It is not unreachable in absolute terms: a system-wide VPN tunnel can still inspect the network traffic those apps generate, which is exactly the approach Part 2 takes. It is just out of reach of anything short of that.
In our hands-on experience, no single API covers the whole problem. Anti-phishing on iOS is a composition exercise: pick the right Apple-provided primitive for each surface, accept the gaps that can't be closed, and reach for heavier machinery only when the gaps actually matter.
This post is the practical guide we wish we'd had when we started. It walks through the two Apple-blessed extensions for content filtering, Safari content blockers and SMS message filter extensions, with the constraints, the trade-offs, and the code that goes with them. In Part 2 we'll cover what happens when those aren't enough and protection has to drop down to the network layer.