Go言語のwebフレームワーク「martini」アプリにBasic認証をかける

martini-contribにauthパッケージが用意されているのでそれを使う。
Basic認証をかける機能しかない。

$ go get github.com/codegangsta/martini-contrib/auth


使い方

package main

import (
	"github.com/codegangsta/martini"
	"github.com/codegangsta/martini-contrib/auth"
)

func main() {
	m := martini.Classic()

	// basic auth
	m.Use(auth.Basic("username", "password"))

	m.Get("/", func() string {
		return "Hello, world"
	})

	m.Run()
}


ソースを読んでいて気がついたこと。

認証文字列が一致するかどうかは単純に==で比較するのではなく、cryptoパッケージのsubtle.ConstantTimeCompareを使っている。
これによって文字列比較にかかる時間からuser/passを推測できないようにしている。
文字列の長さが異なる場合は一致するはずがないけど、同じ理由でわざわざ文字列比較をしてからfalseを返している。

package auth

import (
	"crypto/subtle"
)

// SecureCompare performs a constant time compare of two strings to limit timing attacks.
func SecureCompare(given string, actual string) bool {
	if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
		return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
	} else {

		/* Securely compare actual to itself to keep constant time, but always return false */
		return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
	}
}