ServiceWorkers vs. Network Filtering

In a recent post, I explored how the design of network security features impact the tradeoffs of the system.

In that post, I noted that integrating a URL check directly into the browser provides the security check with the best context, because it allows the client to see the full URL being checked and if a block is needed, a meaningful error page can be shown.

Microsoft Defender SmartScreen and Network Protection are directly integrated into the Edge browser, enabling it to block both known-malicious URLs and those sites that the IT administrator wishes to prohibit in their environment. When a site is blocked from loading in Chrome (or Brave, Firefox, etc) by the lower-level integration into the networking stack, Defender instead shows a Windows toast notification and the main content area of the browser will usually show a low-level networking error (e.g. ERR_SSL_VERSION_OR_CIPHER_MISMATCH).

The team has received a number of customer support requests from customers who find that creating a Microsoft Defender Network Protection custom block for a site doesn’t work as expected in non-Edge browsers. When navigating to the site in Edge, the site is blocked, but when loaded in Chrome, Brave or Firefox, it seems to load despite the block.

What’s happening?

Upon investigating such cases (using Fiddler or the browser’s F12 Network tab), we commonly find that the browser isn’t actually loading the website from the network at all. Instead, the site is being served from within the user’s own browser using a ServiceWorker. You can think of a ServiceWorker (SW) as a modernized and super-powered version of the browser’s cache — the SW can respond to any network request within its domain and generate a response locally without requiring that the request ever reach the network.

For example, consider https://squoosh.app, a site that allows you to see the impact of compressing images using various tools and file formats. When you first visit the site, it provides a hint that it has installed a ServiceWorker by showing a little “Ready to work offline” toast:

This offline-capable notice is something the site itself chooses to show– normally, the browser provides no visible hint that a ServiceWorker is in use unless you open the F12 Developer Tools and choose the Application tab:

Application tab reveals that the current site is using a ServiceWorker

Importantly, after the ServiceWorker has been installed, if you then turn off your WiFi or pull your ethernet cable, you can see that the Squoosh app will continue to work properly. Even if you close your browser and then restart it while offline, you can still visit the Squoosh app and use it.

Because the Squoosh app isn’t loading from the network, network-level blocking by a feature like Network Protection or a block on your corporate gateway or proxy server will not impact the loading of the app so long as its ServiceWorker is installed. Only if the user manually clears the ServiceWorker (e.g. hit Ctrl+Shift+Delete, set the appropriate timeframe, and choose Cookies and other site data):

…is the ServiceWorker removed. Without the ServiceWorker, loading the site results in forcing network requests that can be blocked at the network level by Defender Network Protection:

In contrast to the lower-level network stack blocking, SmartScreen/Network Protection’s integration directly into Edge allows it to monitor all navigations, regardless of whether or not those navigations trigger network requests.

Notably, many ServiceWorker-based apps will load but not function properly when their network requests are blocked. For example, GMail may load when mail.google.com is blocked, but sending and receiving emails will not work, because the page relies upon sending fetch() requests to that origin. When a network-level protection blocks requests, outbound email will linger in the GMail outbox until the blocking is removed. In other cases, like Google Drive, the backing APIs are not located on the drive.google.com origin, so failing to block those API origins might leave Google Drive in a working state even when its primary origin is blocked.

-Eric

Security: The Impact of Time

Two years ago, I wrote a long post about the importance of time, and how practical time machines can help reduce emergencies into more mundane workitems. Today, we revisit the same topic, with a focus on the Security impact of time.

Races

In many ways, the story of modern security is a story about races, with Attackers locked in an endless sprint to outpace Defenders. That’s especially true in the case of phishing and malware — attackers need to get their attack payloads to victims faster than defenders can recognize those payloads and block them.

Defenders work as fast as possible to minimize the time-to-block, but there are three key hurdles that they must leap to get there, each of which takes time:

  • Detection (false-negative reports from users, telemetry, or other sources)
  • Analysis/Grading (manual or automated steps to confirm phishing/malware, determine the scope/rollup of blocks, and reduce the likelihood of false positives)
  • Blocking (authoring and deployment of rules to block malicious content)

Attackers use cloaking and other techniques to try to slow down the process of detection and grading.

Google’s SafeBrowsing team recently claimed that 60% of phishing sites exist for under 10 minutes, giving defender’s precious little time to react before the attackers have moved to a new location and new victims.

Time-to-Check

Another key concern for security is the amount of time a security check requires, and this leads to many design constraints. Users are not willing to accept security solutions that make poor tradeoffs between usability and security, and slow performance can gravely impact usability. Security software must be able to return a verdict (e.g. block or allow) as quickly as possible to keep the user productive.

One common approach to dealing with performance challenges is to make checks asynchronous, such that the user’s activity isn’t blocked until/unless the security check reports a detection of malice. In some cases, this is a smart tradeoff– for example, Microsoft SmartScreen performs asynchronous reputation checks for phishing sites. While it may take a second or two for the online reputation check to complete, a potential-victim is safely navigated to the block page quickly enough that they don’t have the time to type sensitive data (e.g. passwords or credit card info) into the malicious site.

Unfortunately, asynchronous checks aren’t always appropriate. In the case of anti-malware scans or Network Protection checks, we cannot safely allow the malware to run or the malicious connection to be established because the damage could be done before the reputation check completes. So, in most cases, these checks need to be synchronous, which means that they pause the user’s requested activity until the check completes. This creates difficult performance constraints for security software, which otherwise might use relatively slow analysis mechanisms (e.g. “detonation” via sandboxed emulation) to detect malicious content.

These factors mean that security solutions must adopt designs that can meet the time requirements of the user-scenario. Consider Microsoft SmartScreen and Defender Network Protection, two features which are similar except in their time constraints. While SmartScreen performs many URL Reputation checks against the cloud, Network Protection cannot afford such checks. Instead, it consults a locally-cached and frequently updated bloom filter of potentially malicious sites. Only if there’s a match against the bloom filter is the time-expense of a (comparatively slow) online reputation check incurred.

DDoS

Most Distributed Denial of Service (DDoS) attacks (and many Denial of Service attacks in general) are based on attackers sending a huge flurry of requests in a short period of time, forcing legitimate services offline because there’s too much work arriving in too little time. If the attack weren’t concentrated within a short period, it wouldn’t work — the victim service could simply gradually scale up to cover the additional load without much impact.

Unfortunately for defenders, improving performance for legitimate scenarios can result in making attacks more efficient for attackers. A great recent example of this is the “HTTP/2 Rapid Reset” attack. This attack leverages features of the HTTP/2 protocol that were designed to significantly improve performance:

  • Tiny request sizes
  • The ability to layer dozens to hundreds of requests in a single TCP/IP packet
  • The ability to rapidly abandon/cancel requests

… to generate massive load on the recipient CDN or web server.

Crypto

Fireproof safes are rated by how many minutes they can protect their contents in the event of a fire. Most encryption algorithms are based on a similar concept: they aim to protect data longer than the attack lasts.

Given enough time, an attacker can brute force the encryption and discover the secret key that allows them to unscramble protected data. Crypto algorithms are designed to ensure that brute force attacks take impractically long amounts of time (decades or more).

For example, password’s hashes shouldn’t be stored using fast hashes (SHA256), but instead using hashes (Argo2, PBKDF2, BCrypt) that are deliberately designed to be slower.

Even then, defense-in-depth means that we strive to use crypto designs like forward secrecy to protect captured traffic well into the future.

Time Locks

Any interesting use of time is “time locks” whereby time itself is an important component of protection. A business may use a “time lock vaults” which aims to reduce the vulnerable period for a vault. A Time-based One-Time-Password, often used as a second-factor authenticator, uses a clock to generate a one-time-password that is only good for a short validity period.

Many lotteries and casino games depend upon the arrow of time to foil attacks — an attacker cannot steal the winning numbers because the drawing happens in the future and we don’t know of any way to communicate even simple digits to the past.

Cloaking Badness

Defenders routinely run sandboxed security tests on code (e.g. potential malware, potentially-malicious browser extensions, etc) to attempt to determine whether it’s malicious. This process is called detonation. Attackers know that defenders do this and sometimes include logic that attempts to hide bad behavior for longer than a sandboxed-analysis is expected to run. Analysis frameworks respond by doing tricks like advancing the clock, firing timers faster than real-world, etc, in an attempt to trick malware into revealing its misbehavior more quickly. It’s a cat-and-mouse game, and unfortunately, attackers have a distinct advantage, as there are any number of tricks they could use to defer misbehavior until later.

Trust vs. Age

Because defenders strive to kill attacks quickly, there’s a security benefit to treating younger entities (domains, files) with increased suspicion, as older entities are less likely to be undetectedly malicious.

For example, an attacker trying to launch a spear-phishing campaign is likely to register their attack domain (e.g. contoso-auth.xyz) and request its certificate as soon as possible before sending its lures to victims, lest the signals of the coming attack become visible before the attack even begins. For example, there are various monitors that watch for new domain name registrations, and entries into the Certificate Transparency logs that can flag an attack site before it’s even online. Attackers strive to reduce the window of exposure as much as possible to maximize the effective lifetime of their attacks.

To that end, Microsoft Defender’s Web Content Filtering feature offers administrators the option of blocking navigation to domains less than 30 days old, imposing hard constraints on attackers who hope to perform a rapid sneak attack.

Time is fundamental.

-Eric

Beware: URLs are Pointers to Mutable Entities

Folks often like to think of URLs as an entity that can be evaluated: “Is it harmless, or is it malicious?” In particular, vendors of security products tend to lump URLs in with other IoCs (indicators of compromise) like the hash of a known-malicious file, a malicious/compromised digital certificate, or a known-malicious IP address.

Unfortunately, these classes of IoCs are very different in nature. A file’s hash never changes– you can hash a file every second from now until eternity, and every single time you’ll get the same value. A file’s content cannot change without its hash changing, and as a consequence, a “harmless” file can never1 become “malicious” and vice-versa. Note that when we talk about a file here, we’re talking about a specific series of bytes in a particular order, stored anywhere. We’re not talking about a file path, like C:\users\eric\desktop\file.txt which could contain any arbitrary data.

In contrast to a file hash, a network address like an IP or a URL can trivially change from “harmless” to “dangerous” and vice-versa. That’s because, as we saw when we explored the problems with IP reputation, an IP is just a pointer, and a URL is just a pointer-to-a-pointer. The hostname component of a URL is looked up in DNS, and that results in an IP address to which the client makes a network connection. The DNS lookup can return[1] a different IP address every time, and the target server can switch from down-the-block to around-the-world in a millisecond. But that’s just the first pointer. After the client connects to the target server, that server gets to decide how to interpret the client’s request and may choose to return[2] different content every time:

Because the entities pointed at by a pointer can change, a given URL might change from harmless to malicious over time (e.g. a bad guy acquires a domain after its registration expires). But even more surprisingly, a URL can be both harmless and malicious at the same time dependent upon who’s requesting it (e.g. an attacker can “cloak” their attack to return malicious content to targeted victims while serving harmless content to others).

(Aside: A server can even serve a constant response that behaves differently when loaded on each client).

Implications & Attacks

Recently, searching for youtube on Google would result in the first link on the page being a “sponsored” link that looked like this:

If a unsuspecting user clicked on the link, they were taken to a tech scam site that would try to take over the screen and convince the user that they needed to telephone the attacker:

How on earth was this possible? Were the attackers using some sort of fancy Unicode spoofing to make it look like a YouTube link to a human but not to Google’s security checks? Was there a bug on YouTube’s website?

No, nothing so fancy. Attackers simply took advantage of the fact that URLs are pointers to mutable entities.

What almost certainly happened here is that the attacker placed an ad order and pointed it at a redirector that redirected to some page on YouTube. Google’s ad-vetting system checked the URL’s destination to ensure that it really pointed at YouTube, then began serving the ad. The attacker then updated the redirector to point at their scam site, a classic “time-of-check, time-of-use” vulnerability2.

Browser redirect chain upon link click

Because of how the web platform’s security model works, Google’s ability to detect this sort of chicanery is limited– after the user’s browser leaves the googleadservices.com server, Google’s ad engine does not know where the user will end up, and cannot3 know that the next redirector is now sending the user to an attack site.

Now, unfortunately, things are actually a bit worse than I’ve let on so far.

If you’re a “security sensitive” user, you might look at the browser’s status bubble to see where a link goes before you click on it. In this case, the browser claims that the link is pointed at tv.youtube.com:

Our exploration of this attack started at the URL, but there’s actually another level of indirection before that: a link (<a> element) is itself a pointer-to-a-pointer-to-a-pointer. Through JavaScript manipulation, the URL to which a link in a page points can change[0] in the middle of you clicking on it!

And that’s in fact what happens here: Google’s Search results page puts a “placeholder” URL into the <A> until the user clicks on it, at which point the URL changes to the “real” URL:

Now, malicious sites have always been able to spoof the status bubble, but browser vendors expected that “well-behaved sites” wouldn’t do that.

Unfortunately, that expectation turns out to be incorrect.

In this case, showing the “real” URL in the status bubble probably wouldn’t add any protection for our hypothetical “security-conscious” user — all of the links on the Google results page go through some sort of redirector. For example, the legitimate (non-sponsored) search result for YouTube shows www.youtube.com:

…but when clicked, it changes to an inscrutable redirector URL:

… so our theoretical user has no ready way to understand where they’ll end up when clicking on it anyway.

– Eric

1 All absolute statements are incorrect 😂. While a file’s content can’t change, files are typically processed by other code, and that code can change, meaning that a given file can go from harmless to dangerous or vice-versa.

2 It’s entirely possible that Google periodically revalidates the target destination of advertisements, and rather than doing a one-time-switcheroo, the attacker instead cloaked their redirector such that Google graders ended up on YouTube while victims ended up at the tech-scam. There’s some discussion of a similar vector (“tracking templates”).

3 If a user is using Chrome, Google at large could conceivably figure out that the ad was malicious, especially if the redirector ends up landing on a malicious page known by Google Safe Browsing. The SafeBrowsing code integrated into Chrome can “look back” at the redirect chain to determine how a user was lured to a site.

Email Etiquette: Avoid BCC’ing large distribution lists

While Microsoft corporate culture has evolved over the years, and the last twenty years have seen the introduction of new mass communication mechanisms like Yammer and Teams, we remain an email heavy company. Many product teams have related “Selfhost” or “Discussions” aliases (aka “Discussion Lists” or DLs) to which thousands of employees subscribe so they can ask questions and keep an eye on topics relevant to the product.

As a consequence, many employees like me get hundreds or thousands of emails every day, the majority of which I don’t read beyond the subject line. To keep things manageable, I keep a long list of email sorting rules in Outlook designed to sort inbound mails to folders based on whether it was sent directly to me, to a particular alias, etc.

One such rule, which sorts mail from the Edge browser Selfhost alias looks like this:

Generally, this approach works great. However, almost every day there are one or more messages sent by well-meaning employees that drop into my inbox, often beginning with something like:

[BCC’ing the large alias to reduce noise.]

Bill, I’ll take this issue offline and work with you directly to investigate.

Don’t be this guy.

Please, I’m begging you with all of my heart, do not do this!

Despite your best intentions (reducing noise for others), you’re instead dramatically amplifying the prominence of your message.

When you move large DLs to BCC, it has the effect of breaking recipients’ email sorting rules such that it increases the prominence of your email by dropping it in thousands of employee’s inboxes instead of the folders to which the mail would ordinarily be neatly sorted.

Taking an issue “offline” also often has the side-effect of hiding information from everyone else on the alias, and getting information is usually why they joined the alias in the first place!

Instead, please do this:

I’ll investigate this issue with Bill, directly and after we figure out what’s going on, I’ll reply back to the alias with our findings.

Email to Alias

Hey, Bill– Can you try <a,b,c> and send me the log files collected? I’ll take a look at them and figure out what’s going on so I can reply back to the Selfhost alias with the fix timeline and any workarounds.

Email sent only to Bill

Thanks for your help in saving attention!

-Eric


Postscript: There is a mechanism you can use in a rule to detect that you’ve been BCC’d on a message. If you’ve received a message due to a BCC, there will be a message header added:

X-MS-Exchange-Organization-Recipient-P2-Type: Bcc

Allegedly you could put a rule checking for that header before any other sorting rules and Exchange will then try to put BCC’d replies into the same folder as the message being replied to.

I’m going to give this a try, but everything above still stands as this is NOT a trick most users are familiar with.

Update: It didn’t seem to work.

Fiddler Web Debugger Turns 20

Twenty years ago (!!?!) was the first official release of Fiddler. I still run Fiddler for some task or another almost every working day. I still run my version (Fiddler Classic) although some of the newer tools in the Fiddler Universe are compelling for non-Windows platforms.

I presented some slides in a birthday celebration that Progress Telerik streamed online this morning. Those slides might not make sense without the audio, but most of the content is in a presentation I gave at the Codemash conference, and I’ve shared the slides and audio from that talk.

For decades, Fiddler has been a huge part of not only my professional life, but my personal life as well, so this milestone is a bittersweet one. I could write pages, but I won’t. Maybe some day.

Happy birthday, Fiddler, and thank you to everyone who has joined me on the journey over the decades!

-Eric

Security Tradeoffs: Privacy

In a recent post, I explored some of the tradeoffs engineers must make when evaluating the security properties of a given design. In this post, we explore an interesting tradeoff between Security and Privacy in the analysis of web traffic.

Many different security features and products attempt to protect web browsers from malicious sites by evaluating the target site’s URL and blocking access to the site if a reputation service deems the target site malicious: for example, if the site is known to host malware, or perform phishing attacks against victims.

When a web browser directly integrates with a site reputation service, building such a feature is relatively simple: the browser introduces a “throttle” into its navigation or networking stack, whereby URLs are evaluated for their safety, and a negative result causes the browser to block the request or navigate to a warning page. For example, Google Chrome and Firefox both integrate the Google Safe Browsing service, while Microsoft Edge integrates the Microsoft Defender SmartScreen service. In this case, the privacy implications are limited — URL reputation checks might result in the security provider knowing what URLs are visited, but if you can’t trust the vendor of your web browser, your threat model has bigger (insurmountable) problems.

However, beyond direct integration into a browser, there are other architectures.

One choice is to install a security addon (like Microsoft Defender for Chrome or Netcraft) into your browser. In that case, the security addon can collect navigating/downloading URL using the browser’s extension API events and perform its task as if its functionality was directly integrated into the browser. Similarly, Apple offers a new platform API that allows client applications to report URLs they plan to fetch to an extensible lookup service that allows a security provider to indicate whether a given request should be blocked.

In the loosest coupling, a security provider might not integrate into a web browser or client directly at all, instead providing its security at another architectural layer. For example, a provider might watch unencrypted outbound DNS lookups from the PC and block the resolution of hostnames which are known to be malicious. Or, a provider might watch network connections to an outbound site and block connections where the URL or hostname is known to be malicious. This sort of inspection might be achieved by altering the OS networking stack, or plugging into an OS firewall or similar layer.

A common choice is to configure all clients to route their traffic through a proxy or VPN that breaks TLS as a MitM (e.g. Entra Internet Access) and provides the security software access to unencrypted traffic.

The decision of where to integrate security software is a tradeoff between context and generality. The higher you are in the stack, the more context you have (e.g. you may wish to only check URLs for “active” content while ignoring images), while the lower you are in the stack, the more general your solution is (it is less likely to be inadvertently bypassed).

The advantage of integrating security software deep in the OS networking layer is that it can then protect any clients that use the OS networking stack, even if those clients aren’t widely known, and even if the client was written long after your security software was developed. By way of example, Microsoft Defender’s Network Protection and Web Content Filtering features rely upon the Windows Filtering Platform to inspect and block network connections.

For unencrypted HTTP requests, inspecting traffic at the network layer is easy — the URL is found directly in the headers on the outbound request, and because the HTTP traffic is unencrypted plaintext, parsing it is trivial. Unfortunately for security vendors, the story for encrypted HTTPS traffic is much more complicated — the whole point of HTTPS is to prevent a network intermediary (including a firewall, even on the same machine) from being able to read the traffic, including the URL.

To spy on HTTPS from the networking level, a security vendor might reconfigure clients to leak encryption keys, or it might rely on a longstanding limitation in HTTPS to sniff the hostname from the Client Hello message that is sent when the client is setting up the encrypted HTTPS channel with the server.

Security products based on sniffing network traffic (DNS or server connections) are increasingly encountering a sea change: web browser vendors are concerned about improving privacy, and have introduced a number of features to further constrain the ability of a network observer to view what the browser is doing. For example, DNS-over-HTTPS (DoH) means that browsers will no longer send unencrypted hostnames to the DNS server when performing lookups. Instead, a secure HTTPS connection is established to the DNS server, and all requests and responses are encrypted to hide them from network observers.

Additionally, a new feature called Encrypted Client Hello (ECH) means that browsers can no longer spy on the first few packets of a TLS connection to see what server hostname was requested. For example, in loading the https://tls-ech.dev test page with ECH enabled, the client sends a “decoy” Server Name Indicator (SNI) of public.tls-ech.dev rather than the real server name:

When a browser looks up a domain in DNS, the HTTPS Resource Record declares if ECH should be used and if so, the decoy SNI value to send in the OuterHello. You can see this record using a DNS viewer like https://dns.google:

The ECH data is base64-encoded in the record; you can decode it to read the decoy SNI value.

Both Chromium and Firefox have support for ECH. Originally, both DoH and ECH were disabled-by-default in Chrome, Edge, and Firefox for “managed” devices but it appears this may have changed. A test site for ECH can be used to see whether your browser is using ECH, and you can follow these steps to see if a server supports ECH.

A growing percentage of servers support HTTP3/QUIC, an encrypted protocol that runs over UDP. QUIC’s use of “initial encryption” precludes trivial extraction of the server’s name from the UDP packet.

Blinded by these privacy improvements, a security product running at the network level may be fooled and might be forced to fall back to only IP reputation, which suffers many challenges.

Unfortunately, this is a direct tradeoff between security and privacy: security products that aren’t directly integrated into browsers cannot perform their function, but disabling those privacy improvements means that a network-based observer could learn more about what sites users are visiting.

Browser Policies

Browsers offer policies to allow network administrators to make their own tradeoffs by disabling security-software-blinding privacy changes.

Chrome

Edge

Firefox

Safari

  • Current versions of Safari reportedly do not offer a policy to disable QUIC. You may be successful in blocking QUIC traffic at the firewall level (e.g. block UDP traffic to remote port 443).

Stay safe out there!

-Eric

PS: It’s worth understanding the threat scenario here– In this scenario, the network security component inspecting traffic is looking at content from a legitimate application, not from malware. Malware can easily avoid inspection when communicating with its command-and-control (C2) servers by using non-HTTPS protocols, or by routing its traffic through proxies or other communication channel platforms like Telegram, Cloudflare tunnels, or the like.

PPS: Integrating into the browser itself may also be necessary to block sites in situations where a site doesn’t require the network in order to load.

PPPS: Sniffing the SNI is additionally challenging in several other cases:

1) If the browser uses QUIC, the HTTP/3 traffic isn’t going over a traditional TLS-over-TCP channel at all.

2) If the browser is using a VPN service (or equivalent), then the web traffic’s routing information is encrypted before reaching the network stack, and the ClientHello is encrypted and thus the SNI cannot be read.

3) If the browser is connected to a Secure Web Proxy (e.g. TLS-to-the-proxy itself, like the Edge Secure Network feature) then the traffic’s routing information is encrypted before reaching the network stack and ClientHello is encrypted and thus the SNI cannot be read.

4) If the browser uses H/2 Connection coalescing, the browser might reuse a single HTTP/2 connection across multiple different origins. For example, if your admin blocks sports.yahoo.com, you can get around that block by first visiting www.yahoo.com, which creates an unblocked HTTP/2 connection that can be later reused by requests to the Sports.yahoo.com origin.

While an enterprise browser policy is available to disable QUIC, there is not yet a policy to disallow H2 coalescing in Chromium-based browsers. In Firefox, this can be controlled via the network.http.http2.coalesce-hostnames preference.

Security: Tradeoffs

Absolute security is simple– put your PC in a well-guarded vault, and never power it on. But that’s not what PCs are built for, and good luck finding a job that would pay you for such advice. Security Engineering (like all engineering) is a story of tradeoffs. Tradeoffs commonly take place across multiple dimensions:

  • Security
  • Compatibility
  • Performance
  • Ease-of-use
  • Privacy
  • Productivity
  • Cost

As I’ve written recently, the ease-of-use/security tradeoff in the HTML5 Full-screen API leads to a major risk of tech scams. On the other end, the ease-of-use/security tradeoff in the OnBeforeUnload API means that legitimate web applications are harder to use because the platform wants to limit the possibility of abuse.

Recently, an admin reached out to ask about the recommendations in the Microsoft Security Baselines for Edge. In particular, they were curious about why the baselines don’t mandate the disablement of the WebSerial, WebBluetooth, and WebUSB platform APIs, as each of these represents attack surface against devices from the browser, and the Filesystem Access API which could be used to abuse files on the user’s disk.

When an enterprise Security Admin considers whether to disable these APIs via Group Policy, it’s important to consider the full context to decide whether blocking browser APIs will reduce attack surface, or actually increase it.

In this case, these powerful APIs enable browsers to perform tasks that previously required downloading native applications. For example, instead of needing to download some random full-trust native code application to program my kid’s “smart” teddy bear with his name, favorite song, and favorite food:

… I can just go to a website that supports WebUSB, type in the desired information, manually grant the website permission to use WebUSB, and then update the info on the device. The overall attack surface is dramatically reduced by WebUSB, because my task no longer requires running unsandboxed/full-trust code from a teddy bear vendor, who may or may not have good secure development and deployment practices. At worst, I may have to reset my bear, but the browser sandbox means that my PC is not at risk.

Similarly, a few years back, I bought a cheap clock from Alibaba in China.

Setting the time on the clock requires configuration via Bluetooth. Instead of downloading some random full-trust program from an overseas vendor I’ve never heard of, I can use a trivial web app that uses Web Bluetooth to program the device.

Again, there’s no dangerous third-party code running on my PC, and no access to any device is granted unless I specifically choose to allow it.

Ultimately, all features represent attack surface. The key question for security engineers (whether platform engineers or security admins) is whether or not a given feature reduces or improves overall security — its net security impact.

My position is that these APIs, on the whole, improve the security posture of an environment to the extent that they are able to displace higher-risk alternatives (native apps).

Threat Models Aren’t Universal

As we’ve discussed before, however, threat models aren’t one-size-fits-all.

Security Admins must keep in mind that the security baselines are just that, baselines. If their environment is such that they’ve locked down their PCs such that users cannot run native apps of their choosing, then blocking advanced Web APIs probably will not harm their security posture, even if it might harm their users’ productivity.

Follow the Spirit of the Baseline

Admins should further take care to ensure that their use of the baselines maximizes their overall security posture. We recently encountered a customer who had disabled Basic Authentication over HTTP in Edge as a part of following the Edge security baseline:

However, this customer had hundreds of legacy devices that require Basic authentication and are only accessible over HTTP. To enable them to keep working in the face of the baseline’s restriction, the customer configured Edge such that these devices’ IPs would load in Internet Explorer Mode. The customer treated this as a workaround for the Security Baseline. This only worked because they hadn’t also enabled the equivalent WinINET policy that blocks Basic-over-HTTP in IE.

Thus, the customer could claim compliance with the Edge security baseline, but their workaround put the organization at far greater overall risk, because IE Mode represents a huge attack surface. Allowing that attack surface to be combined with MiTM-able HTTP networking means that any network-based attacker could easily exploit vulnerabilities in the legacy IE code, outside of the strong Chromium sandbox in which Edge loads content. The customer would be far more secure if they simply ignored the “No Basic over HTTP” requirement for their unique environment.

Stay safe out there!

-Eric

Web Platform Weirdness: Babies and Bathwater

When moving from other development platforms to the web, developers often have a hard time understanding why the web platform seems so … clunky. In part, that’s because the platform is pretty old at this point (>25 years as an app platform), partly because changes in form factors and paradigms (particular mobile) have introduced new constraints, and partly because the Web is just lousy with bad actors hoping to do bad things.

One “simple thing” desktop developers expect to be able to do is to prompt the user to take some action before leaving an application (e.g. “Save your work?”). For years, browsers offered a simple mechanism for doing so: closing the browser, navigating to a different page, or hitting Refresh button would trigger an OnBeforeUnload() event handler. If the developer’s implementation of that function returned a string, that string would be shown to the user:

Unfortunately, tech scam sites would often abuse this and use it as yet another opportunity to threaten the user, so browsers decided that the most expedient solution was to simply remove the site’s control over the prompt string and show a generic “Changes might not be saved” string, hoping that this reflected the webapp’s true concern:

For the dialog to even display, there must have been an earlier user-gesture on the page; if there was no gesture, the dialog is suppressed entirely.

For some applications, this prompt works just fine, but for complicated workflow applications, the user’s issue might have nothing to do with “saving” anything at all. A user who wants to satisfy the app’s concern must click “Stay on page” and then scroll around to try to figure out where the problem is.

You might hope that you could just update your page’s DOM to show a alert message beside the built in prompt (“Hey, before you go, can you go verify that the setting <X> is what you wanted”, but alas, that doesn’t work — DOM updates are suppressed until after the dialog is dismissed.

Browsers won’t even emit the site’s string into the DevTools console so that an advanced user could figure out what a site was complaining about without manually stepping through the code in a debugger.

Web Platform evangelists tend to reply with workarounds, trying to guide developers to thinking in a more “webby” way (“Oh, just store all the data in indexedDb and restore the state the next time the user visits“), and while well-intentioned, this advice is often hard to follow for one reason or another. So users suffer.

A simple test page.

I’m sad about this state of affairs — I don’t like giving bad guys power over anyone. This truly feels like a case where the web platform threw the baby out with the bathwater, expediently deciding that “We cannot have nice things. No one may speak, because bad people might lie.” The platform could’ve chosen to have a more nuanced policy, e.g. allowing applications to show a string if there was some indication of user trust (e.g. site engagement, installed PWA, etc).

:-(

Web Weirdness: Probing Localhost

If you closely watch the Network tab in the Chromium Developer Tools when you try to log into Fidelity Investments, you might notice something that looks a bit weird. JavaScript on the page attempts to create WebSocket connections to a bunch of local ports on the IPv4 localhost address (127.0.0.1):

So, what are those ports used for? If you look at the website’s source code, you’ll see a clue; each port number in the code is preceded by a short tag of the protocol expected to be listening on that port:

['REF:63333', 'VNC:5900', 'VNC:5901', 'VNC:5902', 'VNC:5903', 'RDP:3389', 'ARO:5950', 'AMY:5931', 'TV0:5939', 'TV1:6039', 'TV2:5944', 'TV2:6040', 'TV3:5938', 'APC:5279', 'ANY:7070', 'ULV:2112']

But why does the website attempt these loopback connections?

The Web Platform does not expose “raw sockets” that would allow the JavaScript to speak any of the protocols in question, and the WebSocket handshake is explicitly designed to prevent using a WebSocket to talk to anything that doesn’t realize it’s speaking to a WebSocket. Furthermore, Chromium has an explicit port block list for well-known ports that are used for protocols that might conceivably be confused by receiving HTTP/HTTPS/WebSocket traffic, and none of these ports are on that list anyway.

So, if the JavaScript cannot hope to communicate using any of the target ports’ expected protocols, why does it even try?

The answer can be found in this great paper from a now-graduated PhD at the Georgia Institute of Technology: Knock and Talk: Investigating Local Network Communications on Websites. As explained in section 4.3, of the 107 sites they found trying to talk to localhost:

+ 36 were for fraud detection,
+ 10 were for bot detection,
+ 12 were communicating with native apps,
+ 44 were likely due to developer error

Knock and Talk: Section 4.3

For the Fidelity case, it seems obvious that they’re probing these ports for fraud detection purposes.

The “Native Apps” case is one I’ve mentioned previously in my Web-to-App Communication Techniques post; the tl;dr is that the Web Platform only exposes a few mechanisms to allow a website to talk to a native application running on the user’s computer, and messaging a localhost server is one of them.

Amusingly, the authors found that, while there’s significant concern about allowing websites this power, then they investigated malicious sites using this technique, those sites were doing so because they were phishing sites that had bulk copied the code from legitimate bank login pages. 🤣

The authors (incorrectly) posit that the probing scripts could detect information about any server running on the target port, but thanks to how WebSocket handshakes work, that’s not possible. Instead, the best the script could do is perform a timing/error analysis to determine whether there’s any service listening on the port [Demo/Article].

Still, it does seem a bit worrisome that web apps can do this sort of probing, and from “inside” the user’s firewall. Because the browser is on localhost, and it’s talking to localhost, most firewalls will ignore the connection attempt and allow it through. If nothing else, this seems like a potential fingerprinting vector, and browser vendors have been working hard to eradicate those.

However, there aren’t necessarily any great options: if we simply blocked access to localhost, any of the scenarios that rely on Web-to-App communication will break. Elsewhere in the Web Platform, there are old and new attempts to isolate the local machine and local network from Internet-sourced web pages. The new proposals rely on CORS preflights, which might be harder to adopt for WebSocket servers, and which might be subject to the same timing analysis already being abused here.

For now, I wouldn’t worry too much about this — it certainly might be scary to see port scans happening from your browser process in your EDR logs, but it should be comforting to know that the browser isn’t actually able to communicate over those ports.

-Eric

Note: This isn’t new. This was an exciting topic back in 2020.

Attack Techniques: Fullscreen Abuse

It’s extremely difficult to prevent attacks when there are no trustworthy pixels on the screen, especially if a user doesn’t realize that none of what they’re seeing should be trusted. Unfortunately for the browsing public, the HTML5 Fullscreen API can deliver this power to an attacker.

Today (and for over a decade now), an attacking website can enter full-screen after any user-gesture, which may be as simple as the user clicking anywhere in the page, or tapping any key. A common threat pattern is to abuse the browser’s APIs to perform a tech scam attack, in which a user is convinced to call a phone number staffed by the attacker.

On initial load, the attack page doesn’t have permission to go full-screen so the address bar and tabs remain visible…
As soon as the user hits any key, the attacker now has the “gesture” they need to abuse browser APIs and go full screen.

As in other hybrid web/phone attacks, after the victim phones the supplied number, the attacker then either directly asks the victim for money to “fix” the PC, or entices the victim to run “remote control” software to grant the attacker control of the PC to steal credentials or install malware. (Aside: The 2024 action thriller The Beekeeper explores what happens if the bad guys accidentally target the friend of a government assassin.)

Attack pages show text in a black box near the top-center of the window to try to confuse the user so they don’t see the browser’s hint that the browser is now in full-screen mode and hitting the Escape key will exit. They make the attack even harder to escape using the Pointer Lock API (which hides the mouse pointer) and the Keyboard Lock API (so exiting fullscreen requires that the user hold the Escape key). They increase the urgency with animation and even a computerized voice claiming that the user’s machine is under attack and they should call immediately to avoid damage. Some attacks will use tricks to cause the browser to become sluggish (e.g. by spamming the IPC channel between the renderer and the browser process) to make it harder for the user to escape the attack page.

If a user even manages to get out of full-screen mode, any keystroke or click re-enters the fullscreen mode. Attempting to close the tab with the [x] button will result in the OnBeforeUnload dialog box, where the user must see and press the Leave button in order to close the page:

OnBeforeUnload confirmation dialog

I built a harmless test page demonstrating some of these techniques.

Making matters even scarier, the attack site may deliver JavaScript which, while (harmlessly) loaded into the browser cache, causes the system’s real security software to pop up a toast indicating that an attack is underway.


What’s a normal human to do in the face of this attack?

One response might be to turn off the power to the computer in the hopes that it will just go away. That might work, at the expense of losing anything that hadn’t been saved, but it might not, if the user accidentally just “sleeps” the device or if the browser’s crash recovery brings the attack site back after the computer reboots.

I recently noticed that the MalwareBytes extension attempts to detect “browser locker” scam sites like these by watching the exercise of certain web-platform APIs. While blocking APIs entirely could have site-compat impact, it might be a reasonable thing to do for many sites on the too-often hostile web.

Punditry

In my opinion, browsers are much too eager to enter and reenter fullscreen – if a user exits full-screen manually, I think we shouldn’t allow the site to regain it without a more explicit user-interaction (e.g. a permission bubble). And browser vendors probably ought to be smarter by paying attention, for example, automatically denying full-screen on sites where the user isn’t a regular visitor.

URL Reputation services like Google Safe Browsing and Microsoft SmartScreen do allow blocking of known tech scam sites, but there are just so so many of them (millions every month).


Update: An End-user Mitigation Appears

Updated: 8/12/2024

Current versions of Chrome have introduced a setting on chrome://flags that helps blunt the risk of the Keyboard Lock API. If you enable this setting:

…and restart your browser, future attempts to invoke the keyboard lock will explicitly prompt before locking the keyboard:

Microsoft Edge Canary (v129.0.2772.0) includes this setting.
Firefox does not (yet?) support the keyboard lock API.

Unfortunately, there’s no option for such a prompt before any random site enters full-screen mode.

Edge’s Scareware Blocker

Updated: 11/21/2025

Edge has introduced a clientside detection for scareware sites. If a scareware attack is detected, the attack is interrupted and the user is presented with an explanatory block page. From that block page, they can report the malicious site to SmartScreen for blocking. Want to know more? Check out a demo video.

-Eric

PS: It’s tempting to think: Can’t the authorities just go after the bad guys on the other end of the phone? That might work, but it’s not a slam dunk.

Some attackers have built their scams in a loosely-coupled way, with plausible deniability at the point where the scam enters “the real world”. They outsource the job of taking money to a company unrelated to the site that scared the user into making the call in the first place. Add to that attackers’ ability to pivot between overseas call centers within hours, and you’ve basically gotten back to the “anti-spam” problem – good guys can take down, at best, a tiny fraction of a percent of the attackers.