92 lines
2.5 KiB
Markdown
92 lines
2.5 KiB
Markdown
|
# Authentication in Golang
|
||
|
|
||
|
## Use header
|
||
|
|
||
|
Use the http header or the body, but avoid using cookies to transport tokens etc
|
||
|
(because of CSRF)
|
||
|
|
||
|
## Implementation
|
||
|
|
||
|
```
|
||
|
# create password/user
|
||
|
update_password(password):
|
||
|
generate salt
|
||
|
db.store(hash(salt + password))
|
||
|
|
||
|
#login
|
||
|
get_token(userId, password):
|
||
|
if not hash(salt + password) == db.get(salted_hash_of_password): # use timing-attack resistant compare here
|
||
|
return FAILED
|
||
|
generate selector
|
||
|
db.store(selector)
|
||
|
generate salt
|
||
|
generate auth_token
|
||
|
db.store(salt, hash(salt+auth_token))
|
||
|
return selector:auth_token
|
||
|
|
||
|
#authenticate
|
||
|
validate_token(selector, auth_token):
|
||
|
if not hash(salt+auth_token) == db.get(salt, salted_hash_of_auth_token WHERE selector): # use timing-attack resistant compare here
|
||
|
return UNKNOWN_TOKEN
|
||
|
return AUTHENTICATED
|
||
|
```
|
||
|
|
||
|
idea: replace selector with userId?
|
||
|
|
||
|
## JWT
|
||
|
|
||
|
```json
|
||
|
{
|
||
|
"userId": "id",
|
||
|
"userRole": "role",
|
||
|
"expiryTime": "now+10min"
|
||
|
}
|
||
|
```
|
||
|
|
||
|
We use JWT with a lifespan of 10min and an in-memory db to blacklist revoked
|
||
|
tokens. So if for e.g. a user changes it's password, we would add the userId and
|
||
|
the time of the change to the blacklist, filtering out all tokens that have been
|
||
|
issued before.
|
||
|
|
||
|
After a server restart, all tokens will become invalid as well, since we can not
|
||
|
be sure which ones were 'on the blacklist'. This could be mitigated by making
|
||
|
the blacklist persistent during restarts.
|
||
|
|
||
|
If a token has expired (either by a server restart or after 10min), a new token
|
||
|
is requested with a 'long lived' refresh-token (lifetime of ~1 week) that is
|
||
|
stored in a database.
|
||
|
|
||
|
### Pros:
|
||
|
|
||
|
- less DB lookups in general
|
||
|
|
||
|
### Cons:
|
||
|
|
||
|
- timestamps of blacklisting could become a problem (maybe add 1 second or use
|
||
|
timestamp returned by n-th node when it has received the update).
|
||
|
- increased load on db + service since we need to issue new jwt for everybody.
|
||
|
|
||
|
## SSL/TLS
|
||
|
|
||
|
```bash
|
||
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout keyFile.key -out certFile.crt
|
||
|
```
|
||
|
|
||
|
## CRIME/BREACH http compression attack
|
||
|
|
||
|
While we do not use a CSRF token, headers sent to the `/api` still contain
|
||
|
private data.
|
||
|
|
||
|
If you are using http/1.1 or lower and have compression enabled on your proxy,
|
||
|
you would be .
|
||
|
|
||
|
## CRSF
|
||
|
|
||
|
We check for a http header like this `X-YOURSITE-CSRF-PROTECTION=1`. This should
|
||
|
be enough, according to
|
||
|
[cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#custom-request-headers)
|
||
|
|
||
|
## XSS
|
||
|
|
||
|
We rely on Vue.js's ability to escape user-input in templates.
|