Update to latest teeny-security: Makes brute-forcing access codes much harder

This commit is contained in:
Daniel Heath 2018-02-15 20:10:27 +11:00
parent 2373e339d0
commit e5dfacb4bb
3 changed files with 26 additions and 6 deletions

2
Gopkg.lock generated
View File

@ -29,7 +29,7 @@
branch = "master"
name = "github.com/danielheath/gin-teeny-security"
packages = ["."]
revision = "5f00fb6ac0933c2b378c907a3e2a43667afc4289"
revision = "b9ad6bd1a94e8e68fd1256221b3e055c8af5f81a"
[[projects]]
name = "github.com/garyburd/redigo"

View File

@ -6,8 +6,9 @@ import "github.com/gin-gonic/gin"
import "github.com/gin-contrib/sessions"
import "net/http"
import "net/url"
import "fmt"
import "io"
import "time"
import "sync"
import "html/template"
// Forces you to a login page until you provide a secret code.
@ -32,6 +33,9 @@ type Config struct {
Template *template.Template
SaveKeyToSession func(*gin.Context, string)
GetKeyFromSession func(*gin.Context) string
LoginAttemptSlowdown time.Duration
mutex sync.Mutex
}
func (c Config) saveKey(ctx *gin.Context, k string) {
@ -58,7 +62,6 @@ func DefaultGetSession(c *gin.Context) string {
session := sessions.Default(c)
str, ok := session.Get("secretAccessCode").(string)
if !ok {
fmt.Println(session.Get("secretAccessCode"))
return ""
}
return str
@ -85,6 +88,13 @@ func (c Config) template() *template.Template {
return c.Template
}
func (c Config) loginSlowdown() time.Duration {
if c.LoginAttemptSlowdown == 0 {
return time.Second
}
return c.LoginAttemptSlowdown
}
func (c Config) ExecTemplate(w io.Writer, message, returnUrl string) error {
return c.template().Execute(w, LoginPageParams{
Message: message,
@ -101,7 +111,7 @@ var DEFAULT_LOGIN_PAGE = template.Must(template.New("login").Parse(`
<h1>Login</h1>
{{ if .Message }}<h2>{{ .Message }}</h2>{{ end }}
<form action="{{.Path}}" method="POST">
<input name="secretAccessCode" />
<input type="password" name="secretAccessCode" />
<input type="submit" value="Login" />
</form>
`))
@ -114,11 +124,14 @@ func (cfg *Config) Middleware(c *gin.Context) {
}
if c.Request.Method == "POST" {
// slow down brute-force attacks
cfg.mutex.Lock()
defer cfg.mutex.Unlock()
time.Sleep(cfg.loginSlowdown())
c.Request.ParseForm()
fmt.Println(c.Request.PostForm.Get("secretAccessCode"))
if c.Request.PostForm.Get("secretAccessCode") == cfg.Secret {
c.Header("Location", returnTo)
cfg.saveKey(c, cfg.Secret)

View File

@ -7,6 +7,8 @@ import "net/http"
import "net/url"
import "log"
import "io"
import "fmt"
import "time"
import "io/ioutil"
import "testing"
import "github.com/gin-gonic/gin"
@ -73,9 +75,14 @@ func TestAuth(t *testing.T) {
mustStartWith("<h1>Login</h1>\n\n<form action=\"/enter-password/?return=%2Fprivate\"", readString(res.Body))
// Check entering a bad password gives you a message
allowedFinishTime := time.Now().Add(time.Second)
res, err = http.PostForm(ts.URL+"/enter-password/", url.Values{"secretAccessCode": []string{"wrong"}})
die(err)
mustStartWith("<h1>Login</h1>\n<h2>Wrong Password</h2>", readString(res.Body))
finishTime := time.Now()
if finishTime.Before(allowedFinishTime) {
die(fmt.Errorf("Expected failed login to take at least 1 second"))
}
// Check entering a good password lets you access things
res, err = http.PostForm(ts.URL+"/enter-password/?return=/private/", url.Values{"secretAccessCode": []string{"garden"}})