Documentation ¶
Overview ¶
Package gosecure provides hashing, checking and associated functions for passphrases and JWT tokens. Tokens allow for session data to be passed in by a client having been encoded earlier. With both hashes and tokens secure cryptographic functions are used. All functions can be called in a time boxed fashion with guarantees about minimum execution time using the Timebox function.
Index ¶
Examples ¶
Constants ¶
const AuthHeader = "Authorization"
AuthHeader is the header used to store the bearer token.
const SessionKey = "session"
SessionKey is used to store a session in a Gorilla context.
Variables ¶
var ( // ErrEmptyPassphrase is returned if an attempt is made to hash an empty // passphrase. ErrEmptyPassphrase = errors.New("security: passphrase cannot be empty") // ErrMismatchedPassphrase is returned if the passphrase does not match the // provided hash. ErrMismatchedPassphrase = errors.New("security: passphrase does not match hash") )
var DefaultAlgorithm = Bcrypt{Cost: bcrypt.DefaultCost}
DefaultAlgorithm is the algorithm used by Hash and Compare.
var ErrNoCredentialsFound = errors.New("no credentials found")
ErrNoCredentialsFound is returned if an attempt is made to validate an empty bearer token.
var Fuse = 100000
Fuse is used to limit the number of hits stored against an action. If the fuse is trigger the action is thrown away. While it's theoretically possible to game the limited by carefully constructing the number of hits vs the limit and TTL in reality the Fuse will only be blown when a DOS style attack is happening and should be well over the limits set on the limiter.
Theoretical max memory usage is Fuse * size * ~60bytes.
Functions ¶
func Compare ¶
Compare a passphrase to a previously hashed passphrase using the default crypto algorithm. If the passphrase matches the hash then this function will return nil. A mismatched passphrase will result in ErrMismatchedPassphrase. All other errors indicate something went wrong comparing the hash and passphrase.
Example ¶
package main import ( "fmt" "bitbucket.org/idomdavis/gosecure" ) func main() { b := []byte{ 36, 50, 97, 36, 49, 48, 36, 100, 117, 66, 70, 85, 103, 120, 51, 68, 80, 106, 103, 108, 90, 74, 84, 51, 101, 56, 57, 122, 79, 87, 122, 74, 122, 51, 46, 108, 82, 73, 106, 56, 115, 101, 88, 112, 85, 46, 68, 67, 112, 78, 48, 121, 67, 97, 57, 109, 74, 98, 114, 67} if err := gosecure.Compare("passphrase", b); err != nil { fmt.Println("invalid passphrase") } else { fmt.Println("passphrase accepted") } }
Output: passphrase accepted
func Hash ¶
Hash a passphrase using the default crypto algorithm.
Example ¶
package main import ( "fmt" "bitbucket.org/idomdavis/gosecure" ) func main() { if h, err := gosecure.Hash("passphrase"); err == nil { fmt.Println(len(h)) } }
Output: 60
func Timebox ¶
Timebox will run the provided function, taking at least the given duration.
Example ¶
package main import ( "fmt" "os" "time" "bitbucket.org/idomdavis/gosecure" ) func main() { // Duration wants to be longer than the expected maximum of the provided // function. duration := time.Millisecond * 50 start := time.Now() // Use closures to send and retrieve values var err error msg := "running..." gosecure.Timebox(duration, func() { _, err = fmt.Fprintln(os.Stdout, msg) }) if err != nil { fmt.Printf("unexpected error running timeboxed function: %s\n", err) } end := time.Now() if (end.Sub(start)) > duration { fmt.Println("time boxed") } }
Output: running... time boxed
Types ¶
type Authenticator ¶
type Authenticator interface { // Authenticate returns a handler function used to authenticate requests. Authenticate(next http.Handler) http.Handler }
Authenticator types provide middleware that will authenticate requests.
func NewAuthenticator ¶
func NewAuthenticator(signatory Signatory) Authenticator
NewAuthenticator returns a type that can be used for authentication middleware.
type Bcrypt ¶
type Bcrypt struct {
Cost int
}
Bcrypt hashing algorithm. Should be all you need.
type Crypto ¶
type Crypto interface { Hash(passphrase string) ([]byte, error) Compare(passphrase string, hash []byte) error }
Crypto defines a type that can cryptographically hash and compare a passphrase. Implementations of Crypto want to implement strong hashing functions such as bcrypt. Implementing this for things like MD5 is a stunningly bad idea.
type Limiter ¶
type Limiter interface { // Limit checks if the action provided should be limited, returning true if // it should. Limit(action string) bool }
A Limiter is used to indicate if an action has occurred too often and should be limited.
func NewLimiter ¶
NewLimiter returns a limiter that uses a lazy LRU backing cache. The limiter prunes expired hits for an action on a call to Limit, and will drop the least recently used item from the cache if it exceeds the defined size.
TTL sizes want to be small (in the 1 second to 1 minute range) to avoid the number of hits in the cache getting too large in case of a DOS style attack. A Fuse value is used to prevent runaway memory consumption in this case.
type RateLimiter ¶
type RateLimiter interface { // Limit returns a handler function used to rate limit requests. Limit(next http.Handler) http.Handler }
RateLimiter defines Gorilla middleware to be used to rate limit requests. If a limiter is triggered it returns "429 Too Many Requests".
func NewSourceLimiter ¶
func NewSourceLimiter(limiter Limiter) RateLimiter
NewSourceLimiter returns middleware that will limit requests based on the remote address, or the source of the request.
func NewUserLimiter ¶
func NewUserLimiter(limiter Limiter) RateLimiter
NewUserLimiter returns middleware that will limit requests based on the user in the basic auth header. If no user is set this limiter is skipped.
type Signatory ¶
type Signatory interface { // Generate a bearer token, embedding the given Session in the token. Generate(data Session) (string, error) // Validate a bearer token, returning the associated Session embedded in the // token. An error is returned if there is a problem validating the token. Validate(bearer string) (Session, error) }
A Signatory is used to sign and validate sessions via the use of JWT bearer tokens.
func NewSignatory ¶
NewSignatory constructs a signatory using the given secret string. If tokens are going to be shared between signatories they must use the same secret.
Example ¶
package main import ( "fmt" "time" "bitbucket.org/idomdavis/gosecure" ) const secret = "secretString" func main() { // Use the default TTL _ = gosecure.NewSignatory(secret, 0) // Specify TTL, generate, then validate a token. sig := gosecure.NewSignatory(secret, time.Hour) token, _ := sig.Generate(gosecure.Session{"key": "value"}) session, _ := sig.Validate(token) fmt.Println(session["key"]) }
Output: value