v147 · Isolated Web Apps · demo
Certificate Flow
How an Isolated Web App uses SecurityInfo from a ControlledFrame HTTPS request to authenticate a parallel Direct Sockets connection to the same server — providing certificate pinning without a custom PKI.
actors
The IWA embeds a <controlledframe> element and navigates it to an HTTPS URL on the remote server. This initiates a browser-verified TLS handshake through Chrome's network stack.
<controlledframe src="https://server.example/">
securityInfoBefore navigating, the IWA registers a webRequest.onHeadersReceived listener with 'securityInfo' in the extraInfoSpec. Chrome populates details.securityInfo with the browser-verified certificate data.
frame.webRequest.onHeadersReceived.addListener(handler, filter, ['securityInfo'])
SecurityInfo.certificates[0].fingerprint.sha256The listener receives the securityInfo object with the verified leaf certificate fingerprint. This fingerprint is exactly what Chrome confirmed via its root trust store — it is not attacker-supplied.
details.securityInfo.certificates[0].fingerprint.sha256
The IWA opens a raw TCP/TLS connection to the server using the Direct Sockets API. The TLS handshake in the raw socket exposes the server's certificate independently of the browser's trust store.
new TCPSocket(host, port, { sslEnabled: true })
Hash the certificate from the Direct Socket TLS handshake and compare it to the fingerprint extracted in step 3. If they match, the IWA can be confident the raw connection reaches the same server Chrome has already authenticated.
if (rawCertSha256 === details.securityInfo.certificates[0].fingerprint.sha256) {…}
before and after Chrome 147
An IWA opening a Direct Socket to a custom-protocol server had no way to verify the TLS certificate independently. It either had to ship its own trust store, use out-of-band key pinning, or accept the risk of connecting to an unauthenticated host.
// No way to get browser-verified cert fingerprint // Must ship own CA or trust blindly const s = new TCPSocket(host, port, { sslEnabled: true }); // ??? how to verify s is the right server?
By routing an HTTPS request through ControlledFrame and reading SecurityInfo, the IWA gets a fingerprint from Chrome's verified TLS session. Any raw socket that presents the same certificate is pinned to the same verified identity.
frame.webRequest.onHeadersReceived.addListener(
(d) => {
const knownFp = d.securityInfo.certificates[0].fingerprint.sha256;
const s = new TCPSocket(host, port, { sslEnabled: true });
// verify s presents same cert as knownFp
},
filter, ['securityInfo']
);
failure branch
If securityInfo is omitted from extraInfoSpec, the request still completes but no browser-verified certificate fingerprint is available. The IWA must block or retry the HTTPS preflight before opening a Direct Socket.
frame.webRequest.onHeadersReceived.addListener(
d => {
if (!d.securityInfo) throw new Error('retry with securityInfo');
},
filter, ['responseHeaders']
);
if (d.securityInfo.state !== 'secure') { blockDirectSocket(host); }
see also
- API Explorer — full SecurityInfo object shape
- Back to feature index
- ChromeStatus entry
scenario focus
Select a scenario to focus its rendered example and summary.