From e74f2210446578248b8d7ac292094e69ca685a8a Mon Sep 17 00:00:00 2001 From: "Thibault \"bui\" Koechlin" Date: Tue, 2 Feb 2021 14:15:13 +0100 Subject: [PATCH] Fix default configurations (#597) * fix default perms on SQLite file * seed the prng securely * fix defaults to enforce certificates verification * ensure file is within path * ensure the directory doesn't exist beforehand * verify certificate by default * disable http ip forward headers --- cmd/crowdsec-cli/config.go | 13 ++++++++---- cmd/crowdsec-cli/machines.go | 21 ++++++++++---------- config/config.yaml | 2 +- config/user.yaml | 2 +- docker/config.yaml | 2 +- docs/v1.X/docs/references/crowdsec-config.md | 2 +- pkg/apiclient/client.go | 2 +- pkg/apiserver/apiserver.go | 4 ++++ pkg/csconfig/config.go | 2 +- pkg/cwhub/download.go | 12 +++++++++-- pkg/database/database.go | 16 +++++++++++++++ 11 files changed, 55 insertions(+), 23 deletions(-) diff --git a/cmd/crowdsec-cli/config.go b/cmd/crowdsec-cli/config.go index 0fc894fa9..dce85e659 100644 --- a/cmd/crowdsec-cli/config.go +++ b/cmd/crowdsec-cli/config.go @@ -5,6 +5,9 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" + + "github.com/pkg/errors" "github.com/crowdsecurity/crowdsec/pkg/csconfig" "github.com/crowdsecurity/crowdsec/pkg/cwhub" @@ -35,11 +38,13 @@ func backupConfigToDirectory(dirPath string) error { return fmt.Errorf("directory path can't be empty") } log.Infof("Starting configuration backup") - _, err = os.Stat(dirPath) - if err == nil { - return fmt.Errorf("%s already exists", dirPath) + /*if parent directory doesn't exist, bail out. create final dir with Mkdir*/ + parentDir := filepath.Dir(dirPath) + if _, err := os.Stat(parentDir); err != nil { + return errors.Wrapf(err, "while checking parent directory %s existence", parentDir) } - if err = os.MkdirAll(dirPath, os.ModePerm); err != nil { + + if err = os.Mkdir(dirPath, 0600); err != nil { return fmt.Errorf("error while creating %s : %s", dirPath, err) } diff --git a/cmd/crowdsec-cli/machines.go b/cmd/crowdsec-cli/machines.go index ac79f0de3..9c49db59a 100644 --- a/cmd/crowdsec-cli/machines.go +++ b/cmd/crowdsec-cli/machines.go @@ -1,10 +1,11 @@ package main import ( + saferand "crypto/rand" "encoding/json" "fmt" "io/ioutil" - "math/rand" + "math/big" "os" "strings" "time" @@ -42,20 +43,18 @@ const ( ) func generatePassword(length int) string { - rand.Seed(time.Now().UnixNano()) + charset := upper + lower + digits + charsetLength := len(charset) buf := make([]byte, length) - buf[0] = digits[rand.Intn(len(digits))] - buf[1] = upper[rand.Intn(len(upper))] - buf[2] = lower[rand.Intn(len(lower))] - - for i := 3; i < length; i++ { - buf[i] = charset[rand.Intn(len(charset))] + for i := 0; i < length; i++ { + rInt, err := saferand.Int(saferand.Reader, big.NewInt(int64(charsetLength))) + if err != nil { + log.Fatalf("failed getting data from prng for password generation : %s", err) + } + buf[i] = charset[rInt.Int64()] } - rand.Shuffle(len(buf), func(i, j int) { - buf[i], buf[j] = buf[j], buf[i] - }) return string(buf) } diff --git a/config/config.yaml b/config/config.yaml index d579b7fd1..73d89eab2 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -31,7 +31,7 @@ db_config: max_age: 7d api: client: - insecure_skip_verify: true + insecure_skip_verify: false credentials_path: /etc/crowdsec/local_api_credentials.yaml server: log_level: info diff --git a/config/user.yaml b/config/user.yaml index 2d8517ad9..362d517b1 100644 --- a/config/user.yaml +++ b/config/user.yaml @@ -27,7 +27,7 @@ db_config: port: 3306 api: client: - insecure_skip_verify: true # default true + insecure_skip_verify: false # default true credentials_path: /etc/crowdsec/local_api_credentials.yaml server: #log_level: info diff --git a/docker/config.yaml b/docker/config.yaml index 1b6864f43..65ea76124 100644 --- a/docker/config.yaml +++ b/docker/config.yaml @@ -31,7 +31,7 @@ db_config: max_age: 7d api: client: - insecure_skip_verify: true + insecure_skip_verify: false credentials_path: /etc/crowdsec/local_api_credentials.yaml server: log_level: info diff --git a/docs/v1.X/docs/references/crowdsec-config.md b/docs/v1.X/docs/references/crowdsec-config.md index cbdcdac2a..e569a1f5e 100644 --- a/docs/v1.X/docs/references/crowdsec-config.md +++ b/docs/v1.X/docs/references/crowdsec-config.md @@ -43,7 +43,7 @@ db_config: max_age: 7d api: client: - insecure_skip_verify: true + insecure_skip_verify: false credentials_path: /etc/crowdsec/local_api_credentials.yaml server: log_level: info diff --git a/pkg/apiclient/client.go b/pkg/apiclient/client.go index c07b53c26..f0bd5ba56 100644 --- a/pkg/apiclient/client.go +++ b/pkg/apiclient/client.go @@ -14,7 +14,7 @@ import ( ) var ( - InsecureSkipVerify = true + InsecureSkipVerify = false ) type ApiClient struct { diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 112f38cb6..8a73f61c4 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -61,6 +61,10 @@ func NewServer(config *csconfig.LocalApiServerCfg) (*APIServer, error) { } log.Debugf("starting router, logging to %s", logFile) router := gin.New() + /*related to https://github.com/gin-gonic/gin/pull/2474 + Gin team doesn't seem to be willing to have a opt-in/opt-out on the trusted proxies. + For now, let's not trust that. */ + router.ForwardedByClientIP = false /*The logger that will be used by handlers*/ clog := log.New() diff --git a/pkg/csconfig/config.go b/pkg/csconfig/config.go index 715e1632f..433783d5d 100644 --- a/pkg/csconfig/config.go +++ b/pkg/csconfig/config.go @@ -125,7 +125,7 @@ func (c *GlobalConfig) LoadConfiguration() error { } } if c.API.Client.InsecureSkipVerify == nil { - apiclient.InsecureSkipVerify = true + apiclient.InsecureSkipVerify = false } else { apiclient.InsecureSkipVerify = *c.API.Client.InsecureSkipVerify } diff --git a/pkg/cwhub/download.go b/pkg/cwhub/download.go index 4bc8b6274..8ee80bc1b 100644 --- a/pkg/cwhub/download.go +++ b/pkg/cwhub/download.go @@ -3,6 +3,7 @@ package cwhub import ( "bytes" "crypto/sha256" + "path/filepath" //"errors" "github.com/pkg/errors" @@ -127,7 +128,6 @@ func DownloadItem(cscli *csconfig.CscliCfg, target Item, overwrite bool) (Item, return target, nil } } - req, err := http.NewRequest("GET", fmt.Sprintf(RawFileURLTemplate, HubBranch, target.RemotePath), nil) if err != nil { return target, errors.Wrap(err, fmt.Sprintf("while downloading %s", req.URL.String())) @@ -159,6 +159,14 @@ func DownloadItem(cscli *csconfig.CscliCfg, target Item, overwrite bool) (Item, tmpdirs := strings.Split(tdir+"/"+target.RemotePath, "/") parent_dir := strings.Join(tmpdirs[:len(tmpdirs)-1], "/") + /*ensure that target file is within target dir*/ + finalPath, err := filepath.Abs(tdir + "/" + target.RemotePath) + if err != nil { + return target, errors.Wrapf(err, "Abs error on %s", tdir+"/"+target.RemotePath) + } + if !strings.HasPrefix(finalPath, tdir) { + return target, fmt.Errorf("path %s escapes %s, abort", target.RemotePath, tdir) + } /*check dir*/ if _, err = os.Stat(parent_dir); os.IsNotExist(err) { log.Debugf("%s doesn't exist, create", parent_dir) @@ -167,7 +175,7 @@ func DownloadItem(cscli *csconfig.CscliCfg, target Item, overwrite bool) (Item, } } /*check actual file*/ - if _, err = os.Stat(tdir + "/" + target.RemotePath); !os.IsNotExist(err) { + if _, err = os.Stat(finalPath); !os.IsNotExist(err) { log.Warningf("%s : overwrite", target.Name) log.Debugf("target: %s/%s", tdir, target.RemotePath) } else { diff --git a/pkg/database/database.go b/pkg/database/database.go index 07e28205e..2681bd028 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -3,6 +3,7 @@ package database import ( "context" "fmt" + "os" "time" "github.com/crowdsecurity/crowdsec/pkg/csconfig" @@ -30,6 +31,21 @@ func NewClient(config *csconfig.DatabaseCfg) (*Client, error) { } switch config.Type { case "sqlite": + + /*if it's the first startup, we want to touch and chmod file*/ + if _, err := os.Stat(config.DbPath); os.IsNotExist(err) { + f, err := os.OpenFile(config.DbPath, os.O_CREATE|os.O_RDWR, 0600) + if err != nil { + return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath) + } + if err := f.Close(); err != nil { + return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath) + } + } else { /*ensure file perms*/ + if err := os.Chmod(config.DbPath, 0600); err != nil { + return &Client{}, fmt.Errorf("unable to set perms on %s: %v", config.DbPath, err) + } + } client, err = ent.Open("sqlite3", fmt.Sprintf("file:%s?_busy_timeout=100000&_fk=1", config.DbPath)) if err != nil { return &Client{}, fmt.Errorf("failed opening connection to sqlite: %v", err)