- Consider https://github.com/peterbourgon/ctxdata for context storage/setting cookies
- DoS
- Lock accounts after failed attempts
- forgotten password tokens (or remeber me, CSRF, etc..) being used as logins (hash them all)
- someone faking a login attempt and that action loging out valid user sessions
- CSRF and XSS using a token and hashed(server-secret + token) token
- Multiple sessions for same account
- Loggout other sessions
- Login as another user
- Multiple user login forms (OAuth2 (https://github.com/volatiletech/authboss/blob/master/oauth2.go), OpenID, Email)
- Merge accounts / multiple login forms for same account
- Remember me
- Server-side forms and SPA's
Four storage interfaces (though 2, 3, & 4 can point to the same store)
- External store for account (provided by implementat)
- Temp session store (prevent CSRF for logins)
- Session store (token -> external.id)
- Remember me store (token -> external.id)
Session (and temp sessions) use browser session cookies that are erased when browser is closed (and server-side when X minutes/hours have passed). This helps prevent our server from filling up from a DoS attack creating millions/billions of sessions.
Remember me store is more DoS safe since only valid login users can populate the store. Therefore we can keep this data around for months without spending much space.
Consider the interfaces needed: https://github.com/volatiletech/authboss/blob/master/user.go
- memory (testing)
- boltdb (one server)
- redis (many servers)
- mysql (many servers)
- An additional cookie token (random) using httpOnly and HTTPS secure only
- This token is stored hashed on the server (so that a DB compromise does not allow the attacker to use it)
- This is a "second" registration system storing where
token -> external.id
to lookup user to create session from and data is kept here for days/weeks
- Non-authenticated sessions should be removed from the system every 5-10 minutes. They only need to last long enough to be used on a login form.
- Invalid login attempts can't terminate valid existing sessions
- Session token is stored in
httpOnly
cookie (prevents XSS) - Nonce token is
hashed(server-secret + session token)
and sent to client
We can set the cookie automatically with a middleware. However, the nonce hash must be inserted into the template or sent to the client manually by the handler.
We can also set the hashed token in a cookie that JS can read so it can pull it out to use in the body or request headers. The server should not look for this hashed value in the cookie to validate the request. It's only there to provide an easy place for the client to fetch it. https://stackoverflow.com/a/39926988/99923
However, please note that this approach means any malicious javascript on the page can read the cookie at any time to find the hashed token and submit that (with the browser providing the main cookie token) to succesfully make a request on behalf of a user.
If the hashed token was only provided once from an endpoint (assuming a SPA here), then Javascript would have to find the value in the React/Angular request object instance and read from there (or use that object itself for the request).
When the request comes in we can write state (or the cookie) to the client automatically using a middleware either before or after the main handler.
- Before the handler might result in data needing to be changed and multiple set-cookie headers sent.
- After the handler the cookie can't be sent because the body was already sent.
The alternative is to have the handler call auther.SendCookies()
when it's ready.
To see if method 1 will work, lets look at the senarios
- user brings valid sesison
- User brings old, expired session (left browser open, but server cleared records) 2.1. with valid remember me?
- User sends no session (closed browser which cleared cookie) 3.1. with valid remember me?
- User sends invalid data (hijacked session?) 4.1. with valid remember me?
In each case it's safe to set a cookie before calling the handler since we are not storing anything but a unique token (and it's hashed version) used by all requests for this client. We can safely set it on the http.ResponseWriter knowing the handler won't need to change anything.
However, we might have two instances that would require a token change:
User sends valid session and 1) requests a LOGOUT or 2) requests a token change (rotating tokens for security?) For LOGOUT, is there some reason to change the token or should we just clear the external storage link and reuse?
https://github.com/qor/auth https://github.com/volatiletech/authboss/
- Requires too much work (implementing too many interfaces)
- multiple Put/INSERT operations per request due to single value->method getter/setter mapping though that might be incorrect as explained here
- No CSRF protection or Double-Submit Cookie support
- Large project to audit
- Authboss reads request looking for input with certain names: https://github.com/volatiletech/authboss/blob/4d85b23e8ac0a6e80e7c76e167bf8043d0836cba/defaults/values.go#L213
- then validates the request fetching the needed data: https://github.com/volatiletech/authboss/blob/master/register/register.go#L75