Expresso.Watch.Host (expresso v0.1.0)

Copy Markdown View Source

Refuses a request for a host other than 127.0.0.1 or localhost

The watch server listens on 127.0.0.1 only, so no other computer can connect. But a web page that the user opens can try DNS rebinding:

  1. The page's host name points to the page's own server.
  2. The host name then changes to point to 127.0.0.1.
  3. The browser now sends the page's requests to the watch server, and the page can read the deck.

Each such request still has the page's host name in its Host header. This module passes a request only when that header is 127.0.0.1 or localhost, with any port. The server answers each other request, and a request with no Host header, with the status 403.

Expresso.Watch.Server puts this module first in the :httpd module list, and :httpd calls do/1 for each request.

Summary

Functions

Tell whether the value of a Host header names this computer

Pass a request with an allowed Host header to the next module

Functions

allowed?(host)

@spec allowed?(String.t()) :: boolean()

Tell whether the value of a Host header names this computer

The port is not part of the check, because a tunnel can use a different port.

iex> Expresso.Watch.Host.allowed?("127.0.0.1:4100")
true

iex> Expresso.Watch.Host.allowed?("LocalHost:8080")
true

iex> Expresso.Watch.Host.allowed?("localhost")
true

iex> Expresso.Watch.Host.allowed?("attacker.example:4100")
false

iex> Expresso.Watch.Host.allowed?("localhost.attacker.example")
false

do(request)

@spec do(tuple()) :: {:proceed, list()} | {:break, [{:response, {403, charlist()}}]}

Pass a request with an allowed Host header to the next module

:httpd calls this function with its mod record. The function returns {:proceed, data} for an allowed host, and a 403 response otherwise.