mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-28 04:05:21 +08:00
improve (crypto): derivate secret_key for each usage to reduce attack surface in the worst case scenario
This commit is contained in:
@ -15,7 +15,6 @@ import (
|
||||
var (
|
||||
Config Configuration
|
||||
configPath string = filepath.Join(GetCurrentDir(), CONFIG_PATH + "config.json")
|
||||
SECRET_KEY string
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
@ -321,7 +320,7 @@ func (this *Configuration) Initialise() {
|
||||
}
|
||||
this.Save()
|
||||
}
|
||||
SECRET_KEY = this.Get("general.secret_key").String()
|
||||
InitSecretDerivate(this.Get("general.secret_key").String())
|
||||
}
|
||||
|
||||
func (this Configuration) Save() Configuration {
|
||||
|
||||
@ -16,4 +16,22 @@ const (
|
||||
URL_SETUP = "/admin/setup"
|
||||
)
|
||||
|
||||
var BUILD_NUMBER string
|
||||
var (
|
||||
BUILD_NUMBER string
|
||||
SECRET_KEY string
|
||||
SECRET_KEY_DERIVATE_FOR_PROOF string
|
||||
SECRET_KEY_DERIVATE_FOR_ADMIN string
|
||||
SECRET_KEY_DERIVATE_FOR_USER string
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
* Improve security by calculating derivative of the secret key to restrict the attack surface
|
||||
* in the worst case scenario with one compromise secret key
|
||||
*/
|
||||
func InitSecretDerivate(secret string) {
|
||||
SECRET_KEY = secret
|
||||
SECRET_KEY_DERIVATE_FOR_PROOF = Hash("PROOF_" + SECRET_KEY, len(SECRET_KEY))
|
||||
SECRET_KEY_DERIVATE_FOR_ADMIN = Hash("ADMIN_" + SECRET_KEY, len(SECRET_KEY))
|
||||
SECRET_KEY_DERIVATE_FOR_USER = Hash("USER_" + SECRET_KEY, len(SECRET_KEY))
|
||||
}
|
||||
|
||||
@ -6,8 +6,7 @@ import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/base32"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@ -45,10 +44,19 @@ func DecryptString(secret string, data string) (string, error){
|
||||
return string(d), nil
|
||||
}
|
||||
|
||||
func Hash(str string) string {
|
||||
hasher := sha1.New()
|
||||
func Hash(str string, n int) string {
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(str))
|
||||
return "sha1::" + base32.HexEncoding.EncodeToString(hasher.Sum(nil))
|
||||
d := hasher.Sum(nil)
|
||||
size := len(Letters)
|
||||
h := ""
|
||||
for i:=0; i<len(d); i++ {
|
||||
if n > 0 && i >= n {
|
||||
break
|
||||
}
|
||||
h += string(Letters[int(d[i]) % size])
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func RandomString(n int) string {
|
||||
@ -140,8 +148,8 @@ func verify(something []byte) ([]byte, error) {
|
||||
|
||||
// Create a unique ID that can be use to identify different session
|
||||
func GenerateID(ctx *App) string {
|
||||
p := ""
|
||||
params := ctx.Session
|
||||
p := "salt => " + SECRET_KEY
|
||||
if params["type"] != "" {
|
||||
p += "type =>" + params["type"]
|
||||
}
|
||||
@ -172,8 +180,10 @@ func GenerateID(ctx *App) string {
|
||||
if params["token"] != "" {
|
||||
p += "token =>" + params["token"]
|
||||
}
|
||||
if p == "salt => " + SECRET_KEY {
|
||||
return ""
|
||||
|
||||
if p == "" {
|
||||
return Hash("N/A", 20)
|
||||
}
|
||||
return Hash(p)
|
||||
p += "salt => " + SECRET_KEY
|
||||
return Hash(p, 20)
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ func AdminSessionGet(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
return c.Value
|
||||
}()
|
||||
|
||||
str, err := DecryptString(SECRET_KEY, obfuscate);
|
||||
str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, obfuscate);
|
||||
if err != nil {
|
||||
SendSuccessResult(res, false)
|
||||
return
|
||||
@ -61,7 +61,7 @@ func AdminSessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Reques
|
||||
|
||||
// Step 3: Send response to the client
|
||||
body, _ := json.Marshal(NewAdminToken())
|
||||
obfuscate, err := EncryptString(SECRET_KEY, string(body))
|
||||
obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, string(body))
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
@ -85,7 +85,7 @@ func AdminBackend(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
if c, err := json.Marshal(backends); err == nil {
|
||||
hash := Hash(string(c))
|
||||
hash := Hash(string(c), 20)
|
||||
if req.Header.Get("If-None-Match") == hash {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
|
||||
@ -92,7 +92,7 @@ func PublicConfigHandler(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
cfg := Config.Export()
|
||||
|
||||
if c, err := json.Marshal(cfg); err == nil {
|
||||
hash := Hash(string(c))
|
||||
hash := Hash(string(c), 20)
|
||||
if req.Header.Get("If-None-Match") == hash {
|
||||
res.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
|
||||
@ -85,7 +85,7 @@ func FileLs(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
Tmp1 interface{}
|
||||
}{ files, perms }
|
||||
if j, err := json.Marshal(tmp); err == nil {
|
||||
return Hash(string(j))
|
||||
return Hash(string(j), 20)
|
||||
}
|
||||
return ""
|
||||
}()
|
||||
|
||||
@ -72,7 +72,7 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
SendErrorResult(res, NewError(err.Error(), 500))
|
||||
return
|
||||
}
|
||||
obfuscate, err := EncryptString(SECRET_KEY, string(s))
|
||||
obfuscate, err := EncryptString(SECRET_KEY_DERIVATE_FOR_USER, string(s))
|
||||
if err != nil {
|
||||
SendErrorResult(res, NewError(err.Error(), 500))
|
||||
return
|
||||
|
||||
@ -44,7 +44,7 @@ func ShareUpsert(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
a, err := req.Cookie(COOKIE_NAME_AUTH)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return a.Value
|
||||
}
|
||||
return ctx.Share.Auth
|
||||
@ -146,7 +146,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
if submittedProof.Key != "" {
|
||||
submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value)
|
||||
submittedProof.Id = Hash(submittedProof.Key + "::" + submittedProof.Value, 20)
|
||||
verifiedProof = append(verifiedProof, submittedProof)
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ func ShareVerifyProof(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
Name: COOKIE_NAME_PROOF,
|
||||
Value: func(p []model.Proof) string {
|
||||
j, _ := json.Marshal(p)
|
||||
str, _ := EncryptString(SECRET_KEY, string(j))
|
||||
str, _ := EncryptString(SECRET_KEY_DERIVATE_FOR_PROOF, string(j))
|
||||
return str
|
||||
}(verifiedProof),
|
||||
Path: COOKIE_PATH,
|
||||
|
||||
@ -30,7 +30,7 @@ func AdminOnly(fn func(App, http.ResponseWriter, *http.Request)) func(ctx App, r
|
||||
return
|
||||
}
|
||||
|
||||
str, err := DecryptString(SECRET_KEY, c.Value);
|
||||
str, err := DecryptString(SECRET_KEY_DERIVATE_FOR_ADMIN, c.Value);
|
||||
if err != nil {
|
||||
SendErrorResult(res, ErrPermissionDenied)
|
||||
return
|
||||
@ -195,7 +195,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
|
||||
var session map[string]string = make(map[string]string)
|
||||
|
||||
if ctx.Share.Id != "" {
|
||||
str, err = DecryptString(SECRET_KEY, ctx.Share.Auth)
|
||||
str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, ctx.Share.Auth)
|
||||
if err != nil {
|
||||
// This typically happen when changing the secret key
|
||||
return session, nil
|
||||
@ -223,7 +223,7 @@ func _extractSession(req *http.Request, ctx *App) (map[string]string, error) {
|
||||
return session, nil
|
||||
}
|
||||
str = cookie.Value
|
||||
str, err = DecryptString(SECRET_KEY, str)
|
||||
str, err = DecryptString(SECRET_KEY_DERIVATE_FOR_USER, str)
|
||||
if err != nil {
|
||||
// This typically happen when changing the secret key
|
||||
return session, nil
|
||||
|
||||
@ -261,7 +261,7 @@ func ShareProofGetAlreadyVerified(req *http.Request) []Proof {
|
||||
if len(cookieValue) > 500 {
|
||||
return p
|
||||
}
|
||||
j, err := DecryptString(SECRET_KEY, cookieValue)
|
||||
j, err := DecryptString(SECRET_KEY_DERIVATE_FOR_PROOF, cookieValue)
|
||||
if err != nil {
|
||||
return p
|
||||
}
|
||||
@ -306,7 +306,7 @@ func shareProofAreEquivalent(ref Proof, p Proof) bool {
|
||||
}
|
||||
for _, chunk := range strings.Split(ref.Value, ",") {
|
||||
chunk = strings.Trim(chunk, " ")
|
||||
if p.Id == Hash(ref.Key + "::" + chunk) {
|
||||
if p.Id == Hash(ref.Key + "::" + chunk, 20) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user