#Plume - Sensible security-headers for Gleam web servers

1 messages · Page 1 of 1 (latest)

polar salmon
#

Hey everyone,

Recently discovered and fell in love with Gleam. Having a blast learning the language and while setting up a web server I noticed there was no helmet.js equivalent with default security headers out-of-the-box.

Threw one together as a little side-quest and thought I'd share it here; works with wisp/mist or anything gleam_http based:

import gleam/http/response.{type Response}
import plume

pub fn handler() -> Response(String) {
  use <- plume.middleware(plume.default())
  response.new(200)
}

Every header (CSP, HSTS, Permissions Policy, etc.) can be customized via the submodules.

Would love any feedback!

https://github.com/scott-ray-wilson/plume

GitHub

Sensible HTTP security headers for Gleam web servers, inspired by helmet. - scott-ray-wilson/plume

cold zodiac
#

It would be great if the README documented what the headers are, what values are used, and the rationale for their design.

#

There's a huge amount of modules for a very tiny API. Would be really nice to merge it all into a single public module.

#

The API is based around a middleware, but looking at the middleware it doesn't actually do anything that requires it to be one. It could be simplified to a function that takes and returns a response

#

Looks like it overrides any existing headers so it would (for example) override Wisp's strong content security policy with its default, which is weaker.

polar salmon
#

Appreciate the prompt feedback @cold zodiac ! I will look into addressing all of these.

As far as the modules go, one of the factors that pushed me towards many vs one was was conflicting types (for example both coop and referrer policy have SameOrigin) - what would your recommendation be here? Just more verbose types?

cold zodiac
#

Yup

#

It’s less verbose for the user that way while also being less to manage

modest plover
#

I think the cool thing is also to have some sensible set of values chosen for me, without having to figure everything out myself
if you went with the fn(Response) -> Response design I could pipe that into a response.set_header afterwards to override your value without you having to type (and provide an option) for all the headers

polar salmon
#

hey @modest plover , just want to make sure I'm tracking your feedback correctly; are you suggesting dropping the configuration all together?

ie plume.set_headers(resp) - which just has the fixed recommend header values instead of the current set_headers with (resp: Response(body), config: Config) -> Response(body)?

modest plover
#

I think that would be better yeah.
From what I can tell you provide all possible values for each header, including a "do not set that at all" option - but I can already do that by going ahead and reading all the mdn docs!
I'm not saying only have a single function; maybe there's multiple different "sensible" sets of configurations? i also think having the middleware as an option isn't too bad too.

One of the hardest problems in security is to get people to pick the secure values. I think your package would be a lot stronger if it didn't allow picking an insecure configuration at all

polar salmon
#

This is great! I do like the idea of a default setter and your last point is valid; thank you, will iterate on this 🙏

#

Currently permissions policy isn't set out-of-the-box since I think it's a little less clear what a sensible default would be but point remains about not needing to specify a config

modest plover
#

thanks 😄

#

yeah maybe documenting it could still be good so people know it exists and where to look?