HappyBee

HappyBee

well, I agree… I’ve no intension of offending anyone. If you get that vibe, I apologize. Thanks for the link though.

2
Post #11
HappyBee

HappyBee

Blog post you had linked, solved the issues with normal http requests, but when there is a websocket upgrade request I still see the server header, how can we remove header even when there is a connection upgrade?

HTTP/1.1 101 Switching Protocols
cache-control: max-age=0, private, must-revalidate
connection: Upgrade
date: XXXX XXX
sec-websocket-accept: VmcZDLx2TP5aKLFproPFiyryze4=
server: Cowboy
upgrade: websocket
0
Post #12
dunson062786

dunson062786

I too am experiencing this issue when there is a websocket upgrade request.

0
Post #13
mithereal

mithereal

there was a couple of pattern matches missing here is an updated plug

defmodule MyApp.Plugs.StripHeaderHandler do
  @behaviour :cowboy_stream

  def info(stream_id, {:response, status, headers, body}, state) do
    headers = Map.drop(headers, ["server"])
    :cowboy_stream.info(stream_id, {:response, status, headers, body}, state)
  end

  def info(stream_id, {:inform, status, headers, body}, state) do
    headers = Map.drop(headers, ["server"])
    :cowboy_stream.info(stream_id, {:response, status, headers, body}, state)
  end

  def info(stream_id, {:switch_protocol, status, headers, body}, state) do
    headers = Map.drop(headers, ["server"])
    :cowboy_stream.info(stream_id, {:response, status, headers, body}, state)
  end

  def info(stream_id, info, state), do: :cowboy_stream.info(stream_id, info, state)
  end

  def init(stream_id, req, opts), do: :cowboy_stream.init(stream_id, req, opts)

  def data(stream_id, is_fin, info, state),
      do: :cowboy_stream.data(stream_id, is_fin, info, state)

  def early_error(stream_id, reason, partial_req, resp, opts),
      do: :cowboy_stream.early_error(stream_id, reason, partial_req, resp, opts)

  def terminate(stream_id, reason, state), do: :cowboy_stream.terminate(stream_id, reason, state)
end
0
Post #14
D4no0

D4no0

Actually this is a very valid point, why do most servers echo the technology behind them? I wonder if there is any real usage to this beside getting sniffed and fingerprinted…

0
Post #15
mithereal

mithereal

you need to add stream handlers under prod http

config :web, Web.Endpoint,
  url: [host: "example.com", port: 80],
  http: [stream_handlers: [:cowboy_compress_h, Web.Plugs.StripHeaderHandler, :cowboy_stream_h]],
  check_origin: false,
  orce_ssl: [rewrite_on: [:x_forwarded_proto]],
  cache_static_manifest: "priv/static/cache_manifest.json",
  socket_options: [:inet6],
  force_ssl: [
    host: nil,
    rewrite_on: [:x_forwarded_port, :x_forwarded_proto],
    # maybe true when we use this for real
    hsts: false
  ]

module


defmodule Web.Plugs.StripHeaderHandler do
  @behaviour :cowboy_stream
  @server_name "my server name"
  @websocket_name :websocket

  def info(stream_id, {:response, status, headers, body}, state) do
    #    headers = Map.drop(headers, ["server"])
    headers = Map.put(headers, "server", @server_name)
    :cowboy_stream.info(stream_id, {:response, status, headers, body}, state)
  end

  def info(stream_id, {:inform, status, headers, _body}, state) do
    status = Map.put(headers, "server", @server_name)
    headers = @websocket_name 
    :cowboy_stream.info(stream_id, {:inform, status, headers}, state)
  end

  def info(stream_id, {:switch_protocol, status, headers, _body}, state) do

    status = Map.put(status, "server", @server_name)
    headers = @websocket_name
    :cowboy_stream.info(stream_id, {:switch_protocol, status, headers}, state)
  end

  def info(stream_id, info, state), do: :cowboy_stream.info(stream_id, info, state)

  def init(stream_id, req, opts), do: :cowboy_stream.init(stream_id, req, opts)

  def data(stream_id, is_fin, info, state),
    do: :cowboy_stream.data(stream_id, is_fin, info, state)

  def early_error(stream_id, reason, partial_req, resp, opts),
    do: :cowboy_stream.early_error(stream_id, reason, partial_req, resp, opts)

  def terminate(stream_id, reason, state), do: :cowboy_stream.terminate(stream_id, reason, state)
end
0
Post #16
s6o

s6o

My updated version, removing the server header without breaking websocket initialisation. In the :switch_protocol headers are in the 2nd element of the tuple. Tested with cowboy 2.12, plug_cowboy 2.7.1, phoenix 1.7.14, phoenix_live_dashboard 0.8.4.

defmodule MyApiWeb.Plugs.StripServerHeader do
  @moduledoc """
  Strip the Cowboy's `server` header from HTTP responses to minimise fingerprinting.
  """
  @behaviour :cowboy_stream

  def info(stream_id, {:response, status, headers, body}, state) do
    headers = Map.drop(headers, ["server"])
    :cowboy_stream.info(stream_id, {:response, status, headers, body}, state)
  end

  def info(stream_id, {:inform, status, headers}, state) do
    headers = Map.drop(headers, ["server"])
    :cowboy_stream.info(stream_id, {:inform, status, headers}, state)
  end

  def info(stream_id, {:switch_protocol, headers, status, body}, state) do
    headers = Map.drop(headers, ["server"])
    :cowboy_stream.info(stream_id, {:switch_protocol, headers, status, body}, state)
  end

  def info(stream_id, info, state) do
    #    IO.inspect(info, label: "strip-header-info")
    :cowboy_stream.info(stream_id, info, state)
  end

  def init(stream_id, req, opts), do: :cowboy_stream.init(stream_id, req, opts)

  def data(stream_id, is_fin, info, state),
    do: :cowboy_stream.data(stream_id, is_fin, info, state)

  def early_error(stream_id, reason, partial_req, resp, opts),
    do: :cowboy_stream.early_error(stream_id, reason, partial_req, resp, opts)

  def terminate(stream_id, reason, state), do: :cowboy_stream.terminate(stream_id, reason, state)
end

The endpoint configuration example:

  config :ov_api, MyApiWeb.Endpoint,
    url: [host: host],
    http: [
      ip: {127, 0, 0, 1},
      port: port,
      stream_handlers: [:cowboy_compress_h, MyApiWeb.Plugs.StripServerHeader, :cowboy_stream_h]
    ],
# ...
0
Post #17
— All posts loaded —