-
Notifications
You must be signed in to change notification settings - Fork 1
Security
Two filters covering the most common cross-cutting HTTP security concerns: CORS (request side) and security headers (response side).
A Tep::Filter subclass that handles preflight (OPTIONS) requests
and adds the right Access-Control-Allow-* headers to actual
responses.
cors = Tep::Security::Cors.new
cors.set_origin("https://app.example.com")
cors.set_allowed_verbs("GET,POST,PUT,DELETE")
cors.set_allowed_headers("Content-Type,Authorization")
cors.set_max_age(3600)
before do
cors.before(request, response)
endFor a fully-open API (development, or genuinely public endpoints):
cors.set_origin("*")For a per-route policy, branch on request.path in the filter
block.
- On a preflight
OPTIONSrequest: writes theAccess-Control-Allow-{Origin,Methods,Headers,Max-Age}headers and halts with 204. - On any other request: adds
Access-Control-Allow-OriginandVary: Originto the response. The actual handler still runs.
Default security headers, applied as an after filter. Sensible
defaults out of the box; tuneable for apps that want non-defaults.
hdr = Tep::Security::Headers.new
hdr.set_hsts(63072000) # default; set to 0 to disable
after do
hdr.after(request, response)
end| Header | Value |
|---|---|
Strict-Transport-Security |
max-age=<hsts_seconds>; includeSubDomains |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Referrer-Policy |
strict-origin-when-cross-origin |
X-Permitted-Cross-Domain-Policies |
none |
It does NOT set Content-Security-Policy — that's app-specific
and varies enough that a default would do more harm than good.
Write your own:
after do
response.headers["Content-Security-Policy"] = "default-src 'self'"
Tep::Security::Headers.new.after(request, response)
endhdr = Tep::Security::Headers.new
hdr.set_hsts(63072000)
before do
if !request.ssl? # checks X-Forwarded-Proto
redirect "https://" + request.host + request.path
end
end
after do
hdr.after(request, response)
endrequest.ssl? reads X-Forwarded-Proto; the proxy needs to be
configured to set it. On nginx: proxy_set_header X-Forwarded-Proto $scheme;.
hdr = Tep::Security::Headers.new
if ENV.fetch("APP_ENV", "production") == "development"
hdr.set_hsts(0)
end
after do
hdr.after(request, response)
end-
cors.beforeis a NOOP on missingOrigin. Same-origin requests don't get the CORS header machinery — by design. -
HSTSis cumulative. Once a browser sees it, it'll refuse plaintext for the duration; rolling back to HTTP-only requires servingmax-age=0for the same length of time, then waiting. Test in a separate hostname first. -
Frame-Options: DENYblocks<iframe>embedding. If your app intentionally embeds itself somewhere, override toSAMEORIGIN(and consider migrating to CSP'sframe-ancestors).