1
0
mirror of https://github.com/schollz/cowyo.git synced 2023-08-10 21:13:00 +03:00

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" branch = "master"
name = "github.com/danielheath/gin-teeny-security" name = "github.com/danielheath/gin-teeny-security"
packages = ["."] packages = ["."]
revision = "5f00fb6ac0933c2b378c907a3e2a43667afc4289" revision = "b9ad6bd1a94e8e68fd1256221b3e055c8af5f81a"
[[projects]] [[projects]]
name = "github.com/garyburd/redigo" name = "github.com/garyburd/redigo"

View File

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

View File

@ -7,6 +7,8 @@ import "net/http"
import "net/url" import "net/url"
import "log" import "log"
import "io" import "io"
import "fmt"
import "time"
import "io/ioutil" import "io/ioutil"
import "testing" import "testing"
import "github.com/gin-gonic/gin" 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)) mustStartWith("<h1>Login</h1>\n\n<form action=\"/enter-password/?return=%2Fprivate\"", readString(res.Body))
// Check entering a bad password gives you a message // 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"}}) res, err = http.PostForm(ts.URL+"/enter-password/", url.Values{"secretAccessCode": []string{"wrong"}})
die(err) die(err)
mustStartWith("<h1>Login</h1>\n<h2>Wrong Password</h2>", readString(res.Body)) 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 // Check entering a good password lets you access things
res, err = http.PostForm(ts.URL+"/enter-password/?return=/private/", url.Values{"secretAccessCode": []string{"garden"}}) res, err = http.PostForm(ts.URL+"/enter-password/?return=/private/", url.Values{"secretAccessCode": []string{"garden"}})