How do I generate a unique token (for e-mail verification)? - random

I want to implement a system that after user signs up, user will receive an email includes a link to verify this email is for that user.
The way I generate the token for verifying the email is like this:
import (
"crypto/rand"
"encoding/base64"
)
func generateToken() (string, error) {
b := make([]byte, 35)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b), nil
}
But what I want to ask is if this method is OK? How to make all the token generated by this method is unique ?
What is the normal way to implement this system ?
Please give me some ideas and tell me if this method of generating token is good.
Thanks.

Check out https://pkg.go.dev/github.com/google/uuid#NewRandom.
And you may want to consider storing this in a database with the email address and perhaps an expiry date / time so that the verification doesn't stay there forever. You may only want to allow people to verify within 24 hours, or 7 days and so on. Have another job that periodically cleans expired and non-verified emails.

Two points:
No, the method as presented won't guarantee them to be unique.
You don't need to have all your tokens to be unique.
To expand on these points…
You're dealing with a set of outstanding verification requests.
That is:
A request is made by the user;
You generate a unique verification token and store it into some presistent database. This is needed in order for verification to work anyway.
The user receives your e-mail and clicks that link from it which contain your token. At this point you remove the information about this pending verificaton request from your persistent storage.
As you can see, at any given time you only have several outstanding verification requests. Hence this situation has two important properties:
You only need the tokens of these outstanding requests be different from one another. It's OK to have a verification token to be the same as that of some past (or future) request.
Your tokens have to be hard-to-guess (obviously). I'm sure you already understand that.
So, the approach to generating a new token is as follows:
Generate something hard-to-guess.
Compare it with the tokens bound to the outstanding/pending verification requests persisted in your storage.
If you find an outstanding request with the same token, you have a collision so go to step (1) and repeat.
Otherwise the token is OK so proceed with it and persist the data about this request.
Once the request passed verification, remove it from your storage.
Exact algorythm for generating tokens does not matter much. I'd say an UUID or something looking like SHA-256/512 calculated over some random data is OK.

Related

Efficiently skipping Stripe API calls and/or logging for test IDs

I would like to be able to have test stripe accounts live along production accounts in the same database, but treat them differently depending on whether I am using test API keys.
Currently the stripe Go library logs errors when a test Stripe ID is queried while using production API keys. The Stripe library itself logs this when trying to fetch such a stripe customer:
Error encountered from Stripe: {"code":"resource_missing","status":404,"message":
"No such customer: cus_foo; a similar object exists in test mode, but a live mode
key was used to make this request.","param":"id","request_id":"req_foo","type":
"invalid_request_error"}
I would like to avoid having this happen by either doing a separate API call that asks "is this a test user?" or by suppressing only the above error output so I can ignore and not print my own error in the case of test users.
I do the obvious
params := &stripe.CustomerParams{}
stripeCustomer, err := customer.Get(stripeID, params)
if err != nil {
return nil, err
}
From a function, but the call to Get() has already logged an error before I have a chance to react to it..
I could just have a test_account attribute attached to the user, but I'd rather just make a few needless API calls and silently ignore them somehow.

best way to store a single time use record in redis using golang

I am using golang and go-redis package
I would like to store a key-value pair in redis (e.g one time token). When this token is read, I generate a permanent token. But the one time token should be deleted once I have read the value. This is to avoid fast-replay attack. What is the best way to implement this. I have been thinking of mutex.
This is a perfect use case for the MULTI-EXEC functionality:
MULTI
GET key
DELETE key
EXEC
Or in go:
pipe := client.TxPipeline()
get := pipe.Get("key")
pipe.Del("key")
_, err := pipe.Exec()
fmt.Println(get.Val(), err)
This will ensure that both commands execute in a transaction, so the key will either be retrieved and deleted or not retrieved at all.

Storing request and session ID in context.Context considered bad?

There is this excellent blog post by Jack Lindamood How to correctly use context.Context in Go 1.7 which boils down to the following money quote:
Context.Value should inform, not control. This is the primary mantra that I feel should guide if you are using context.Value correctly. The
content of context.Value is for maintainers not users. It should never
be required input for documented or expected results.
Currently, I am using Context to transport the following information:
RequestID which is generated on the client-side passed to the Go backend and it solely travels through the command-chain and is then inserted in the response again. Without the RequestID in the response, the client-side would break though.
SessionID identifies the WebSocket session, this is important when certain responses are generated in asynchronous computations (e.g. worker queues) in order to identify on which WebSocket session the response should be send.
When taking the definition very seriously I would say both violate the intention of context.Context but then again their values do not change any behavior while the whole request is made, it's only relevant when generating the response.
What's the alternative? Having the context.Context for metadata in the server API actually helps to maintain lean method signatures because this data is really irrelevant to the API but only important for the transport layer which is why I am reluctant to create something like a request struct:
type Request struct {
RequestID string
SessionID string
}
and make it part of every API method which solely exists to be passed through before sending a response.
Based on my understanding context should be limited to passing things like request or session ID. In my application, I do something like below in one of my middleware. Helps with observability
if next != nil {
if requestID != "" {
b := context.WithValue(r.Context(), "requestId", requestID)
r = r.WithContext(b)
}
next.ServeHTTP(w, r)
}

Phil Strugeon REST server - is there really security vulnerability in Digest Auth or I misunderstood something?

Recently I downloaded Phil Strugeon REST server for CodeIgniter.
I reviewed source code and when I come to Digest authentication I saw following code:
if ($this->input->server('PHP_AUTH_DIGEST'))
{
$digest_string = $this->input->server('PHP_AUTH_DIGEST');
}
elseif ($this->input->server('HTTP_AUTHORIZATION'))
{
$digest_string = $this->input->server('HTTP_AUTHORIZATION');
}
else
{
$digest_string = "";
}
And bit later after some checks for absence of $digest_string and presence of username:
// This is the valid response expected
$A1 = md5($digest['username'].':'.$this->config->item('rest_realm').':'.$valid_pass);
$A2 = md5(strtoupper($this->request->method).':'.$digest['uri']);
$valid_response = md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);
if ($digest['response'] != $valid_response)
{
header('HTTP/1.0 401 Unauthorized');
header('HTTP/1.1 401 Unauthorized');
exit;
}
In Wikipedia I see following text about HTTP Digest Auth:
For subsequent requests, the hexadecimal request counter (nc) must be greater than the last value it used – otherwise an attacker could simply "replay" an old request with the same credentials. It is up to the server to ensure that the counter increases for each of the nonce values that it has issued, rejecting any bad requests appropriately.
The server should remember nonce values that it has recently generated. It may also remember when each nonce value was issued, expiring them after a certain amount of time. If an expired value is used, the server should respond with the "401" status code and add stale=TRUE to the authentication header, indicating that the client should re-send with the new nonce provided, without prompting the user for another username and password.
However I can't see anything about checking cnonce, nc or nonce in source code.
Does it mean that somebody who recorded request from Client to Server that passed authentification may just "replay" it in future and receive fresh value of resource?
Is it really vulnarability? Or I misunderstood something?
I noticed this too when looking at codeigniter-restserver. It IS vulnerable to replay attacks because, as you said, it does not enforce the nonce.
Digest authentication requires a handshake:
client makes request with Authorization. It will fail because the client does not yet know the nonce
server responds with WWW-Authenticate header, that contains the correct nonce to use
client makes same request using the nonce provided in the server response
server checks that the nonces match and provides the requested url.
To accomplish this, you'll need to start a session on your REST server to remember the nonce. An easy scheme for ensuring nonce is always unique is to base it on current time using a function such as uniqid()

Go session variables?

I'm new to the Go language (Golang) and I'm writing a web-based application. I'd like to use session variables, like the kind in PHP (variables that are available from one page to the next and unique for a user session). Is there something like that in Go? If not, how would I go about implementing them myself? Or what alternatives methods are there?
You probably want to take a look at gorilla. It has session support as documented here.
Other than that or possibly one of the other web toolkits for go you would have to roll your own.
Possible solutions might be:
goroutine per user session to store session variables in memory.
store your variables in a session cookie.
use a database to store user session data.
I'll leave the implementation details of each of those to the reader.
Here's an alternative in case you just want session support without a complete web toolkit.
https://github.com/bpowers/seshcookie
Here's another alternative (disclosure: I'm the author):
https://github.com/icza/session
Quoting from its doc:
This package provides an easy-to-use, extensible and secure session implementation and management. Package documentation can be found and godoc.org:
https://godoc.org/github.com/icza/session
This is "just" an HTTP session implementation and management, you can use it as-is, or with any existing Go web toolkits and frameworks.
Overview
There are 3 key players in the package:
Session is the (HTTP) session interface. We can use it to store and retrieve constant and variable attributes from it.
Store is a session store interface which is responsible to store sessions and make them retrievable by their IDs at the server side.
Manager is a session manager interface which is responsible to acquire a Session from an (incoming) HTTP request, and to add a Session to an HTTP response to let the client know about the session. A Manager has a backing Store which is responsible to manage Session values at server side.
Players of this package are represented by interfaces, and various implementations are provided for all these players.
You are not bound by the provided implementations, feel free to provide your own implementations for any of the players.
Usage
Usage can't be simpler than this. To get the current session associated with the http.Request:
sess := session.Get(r)
if sess == nil {
// No session (yet)
} else {
// We have a session, use it
}
To create a new session (e.g. on a successful login) and add it to an http.ResponseWriter (to let the client know about the session):
sess := session.NewSession()
session.Add(sess, w)
Let's see a more advanced session creation: let's provide a constant attribute (for the lifetime of the session) and an initial, variable attribute:
sess := session.NewSessionOptions(&session.SessOptions{
CAttrs: map[string]interface{}{"UserName": userName},
Attrs: map[string]interface{}{"Count": 1},
})
And to access these attributes and change value of "Count":
userName := sess.CAttr("UserName")
count := sess.Attr("Count").(int) // Type assertion, you might wanna check if it succeeds
sess.SetAttr("Count", count+1) // Increment count
(Of course variable attributes can be added later on too with Session.SetAttr(), not just at session creation.)
To remove a session (e.g. on logout):
session.Remove(sess, w)
Check out the session demo application which shows all these in action.
Google App Engine support
The package provides support for Google App Engine (GAE) platform.
The documentation doesn't include it (due to the +build appengine build constraint), but here it is: gae_memcache_store.go
The implementation stores sessions in the Memcache and also saves sessions to the Datastore as a backup in case data would be removed from the Memcache. This behaviour is optional, Datastore can be disabled completely. You can also choose whether saving to Datastore happens synchronously (in the same goroutine) or asynchronously (in another goroutine), resulting in faster response times.
We can use NewMemcacheStore() and NewMemcacheStoreOptions() functions to create a session Store implementation which stores sessions in GAE's Memcache. Important to note that since accessing the Memcache relies on Appengine Context which is bound to an http.Request, the returned Store can only be used for the lifetime of a request! Note that the Store will automatically "flush" sessions accessed from it when the Store is closed, so it is very important to close the Store at the end of your request; this is usually done by closing the session manager to which you passed the store (preferably with the defer statement).
So in each request handling we have to create a new session manager using a new Store, and we can use the session manager to do session-related tasks, something like this:
ctx := appengine.NewContext(r)
sessmgr := session.NewCookieManager(session.NewMemcacheStore(ctx))
defer sessmgr.Close() // This will ensure changes made to the session are auto-saved
// in Memcache (and optionally in the Datastore).
sess := sessmgr.Get(r) // Get current session
if sess != nil {
// Session exists, do something with it.
ctx.Infof("Count: %v", sess.Attr("Count"))
} else {
// No session yet, let's create one and add it:
sess = session.NewSession()
sess.SetAttr("Count", 1)
sessmgr.Add(sess, w)
}
Expired sessions are not automatically removed from the Datastore. To remove expired sessions, the package provides a PurgeExpiredSessFromDSFunc() function which returns an http.HandlerFunc. It is recommended to register the returned handler function to a path which then can be defined as a cron job to be called periodically, e.g. in every 30 minutes or so (your choice). As cron handlers may run up to 10 minutes, the returned handler will stop at 8 minutes
to complete safely even if there are more expired, undeleted sessions. It can be registered like this:
http.HandleFunc("/demo/purge", session.PurgeExpiredSessFromDSFunc(""))
Check out the GAE session demo application which shows how it can be used.
cron.yaml file of the demo shows how a cron job can be defined to purge expired sessions.
Check out the GAE session demo application which shows how to use this in action.

Resources