6 Best Security Practices für unterwegs

Eine Übersetzung des Artikels wurde speziell für Studenten des Golang Developer- Kurses erstellt .





Die Popularität von Golang hat in den letzten Jahren erheblich zugenommen. Erfolgreiche Projekte wie Docker , Kubernetes und Terraform haben eine große Wette auf diese Programmiersprache abgeschlossen. Go ist seit kurzem der De-facto-Standard für die Erstellung von Befehlszeilentools. In Bezug auf die Sicherheit hat Go gemäß seinen Schwachstellenberichten erfolgreich verwaltet und verfügt seit 2002 nur über eine CVE-Registrierung .

Das Fehlen von Sicherheitslücken bedeutet jedoch nicht, dass die Programmiersprache sehr sicher ist. Wir Menschen können unsichere Anwendungen erstellen, wenn wir bestimmte Regeln nicht befolgen. Zum Beispiel die Regeln zum Schreiben von sicherem Code aus OWASP kennenkönnen wir darüber nachdenken, wie diese Methoden bei Verwendung von Go angewendet werden. Und genau das werde ich diesmal tun. In diesem Beitrag zeige ich Ihnen sechs Vorgehensweisen, die Sie bei der Entwicklung mit Go berücksichtigen sollten.

1. Überprüfen Sie die Eingabe


Die Überprüfung der Benutzereingaben ist nicht nur für funktionale Zwecke erforderlich, sondern hilft auch, Angriffe von Cyberkriminellen zu vermeiden, die uns aufdringliche Daten senden, die das System beschädigen könnten. Darüber hinaus helfen Sie Benutzern, dieses Tool sicherer zu verwenden, und verhindern so, dass sie dumme und häufige Fehler machen. Sie können beispielsweise verhindern, dass ein Benutzer versucht, mehrere Einträge gleichzeitig zu löschen.

Um Benutzereingaben zu testen, können Sie native Go-Pakete wie strconv verwenden, um die Konvertierung von Zeichenfolgen in andere Datentypen zu handhaben. Go unterstützt auch reguläre Ausdrücke mit regexpfür komplexe Prüfungen. Obwohl Go lieber native Bibliotheken verwendet, gibt es Pakete von Drittanbietern wie Validator. Mit validator können Sie die Validierung für Strukturen oder einzelne Felder viel einfacher aktivieren. Der folgende Code überprüft beispielsweise, ob die Struktur Usereine gültige E-Mail-Adresse enthält:

package main

import (
	"fmt"

	"gopkg.in/go-playground/validator.v9"
)

type User struct {
	Email string `json:"email" validate:"required,email"`
	Name  string `json:"name" validate:"required"`
}

func main() {
	v := validator.New()
	a := User{
		Email: "a",
	}

	err := v.Struct(a)

	for _, e := range err.(validator.ValidationErrors) {
		fmt.Println(e)
	}
}


2. Verwenden Sie HTML-Vorlagen


Eine häufige kritische Sicherheitsanfälligkeit ist Cross-Site-Scripting oder XSS. Der Haupt-Exploit besteht darin, dass ein Angreifer schädlichen Code in die Anwendung einfügen kann, um die Ausgabe zu ändern. Beispielsweise kann jemand JavaScript-Code als Teil einer Abfragezeichenfolge in einer URL senden. Wenn die Anwendung den Wert des Benutzers zurückgibt, kann JavaScript-Code ausgeführt werden. Daher sollten Sie als Entwickler diese Möglichkeit kennen und die vom Benutzer eingegebenen Daten löschen.

Go verfügt über ein HTML / Template- Paket, mit dem codiert werden kann, was die Anwendung an den Benutzer zurückgibt. Also anstatt dass der Browser Eingaben wie macht<script>alert(‘ !’);</script>er wird eine Warnung geben; Sie können die Eingabe codieren, und die Anwendung verarbeitet die Eingabe als typischen HTML-Code, der in einem Browser gedruckt wird. Ein HTTP-Server, der eine HTML-Vorlage zurückgibt, sieht folgendermaßen aus:

package main

import (
	"html/template"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	param1 := r.URL.Query().Get("param1")
	tmpl := template.New("hello")
	tmpl, _ = tmpl.Parse(`{{define "T"}}{{.}}{{end}}`)
	tmpl.ExecuteTemplate(w, "T", param1)
}
func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}


Es gibt jedoch Bibliotheken von Drittanbietern, die Sie beim Entwickeln von Webanwendungen auf Go verwenden können. Zum Beispiel das Gorilla-Web-Toolkit , das Bibliotheken enthält, mit denen Entwickler beispielsweise Cookie-Authentifizierungswerte codieren können. Es gibt auch Nosurf , ein HTTP-Paket, das dazu beiträgt, Cross-Site Request Forgery ( CSRF ) zu verhindern.

3. Schützen Sie sich vor SQL-Injection


Wenn Sie schon länger entwickelt haben, kennen Sie möglicherweise SQL-Injektionen, die immer noch die erste Position in der OWASP-Spitze einnehmen . Es gibt jedoch einige spezifische Punkte, die Sie bei der Verwendung von Go berücksichtigen sollten. Als erstes müssen Sie sicherstellen, dass der Benutzer, der eine Verbindung zur Datenbank herstellt, über eingeschränkte Rechte verfügt. Es wird auch empfohlen, Benutzereingaben zu bereinigen, wie im vorherigen Abschnitt beschrieben, oder Sonderzeichen zu umgehen und die Funktion HTMLEscapeString aus dem HTML-Vorlagenpaket zu verwenden.

Der wichtigste Code, den Sie einschließen müssen, ist jedoch die Verwendung parametrisierter Abfragen. In Go bereiten Sie keinen Ausdruck vor (dies ist eine vorbereitete Anweisung) in Verbindung; Sie bereiten es in der Datenbank vor. Hier ist ein Beispiel für die Verwendung parametrisierter Abfragen:

customerName := r.URL.Query().Get("name")
db.Exec("UPDATE creditcards SET name=? WHERE customerId=?", customerName, 233, 90)


Was ist jedoch, wenn das Datenbankmodul die Verwendung vorbereiteter Ausdrücke nicht unterstützt? Oder was ist, wenn es die Abfrageleistung beeinträchtigt? Nun, Sie können die Funktion db.Query () verwenden, aber stellen Sie zunächst sicher, dass Sie die Benutzereingaben bereinigen, wie in den vorherigen Abschnitten gezeigt. Es gibt auch Bibliotheken von Drittanbietern wie sqlmap , um die SQL-Injection zu verhindern.

Trotz aller Bemühungen rutschen manchmal Schwachstellen aus oder werden über Dritte in unsere Anwendungen eingegeben. Um Ihre Webanwendungen vor kritischen Angriffen wie SQL Injection zu schützen, sollten Sie eine Anwendungssicherheitsverwaltungsplattform wie Sqreen verwenden .

4. Verschlüsseln Sie vertrauliche Informationen


Die Tatsache, dass die Zeichenfolge beispielsweise im Base-64-Format schwer zu lesen ist, bedeutet nicht, dass der verborgene Wert geheim ist. Sie benötigen eine Möglichkeit, Informationen zu verschlüsseln, die Angreifer nicht einfach entschlüsseln können. Typische Informationen, die Sie verschlüsseln möchten, sind Datenbankkennwörter, Benutzerkennwörter oder sogar Sozialversicherungsnummern.

Das OWASP enthält mehrere Empfehlungen dazu, welche Verschlüsselungsalgorithmen beispielsweise verwendet bcryptwerden PDKDF2, Argon2oder scrypt. Glücklicherweise gibt es ein Go-Paket, das zuverlässige Implementierungen zum Verschlüsseln von Informationen enthält - Krypto . Der folgende Code ist ein Beispiel für die Verwendung bcrypt:

package main

import (
	"database/sql"
	"context"
	"fmt"

	"golang.org/x/crypto/bcrypt"
)

func main() {
	ctx := context.Background()
	email := []byte("john.doe@somedomain.com")
	password := []byte("47;u5:B(95m72;Xq")

	hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
	if err != nil {
		panic(err)
	}

	stmt, err := db.PrepareContext(ctx, "INSERT INTO accounts SET hash=?, email=?")
	if err != nil {
		panic(err)
	}
	result, err := stmt.ExecContext(ctx, hashedPassword, email)
	if err != nil {
		panic(err)
	}
}


Bitte beachten Sie, dass Sie beim Übertragen von Informationen zwischen Diensten immer noch Vorsicht walten lassen müssen. Sie möchten keine Benutzerdaten im Klartext senden. Es spielt keine Rolle, ob die Anwendung Benutzerdaten vor dem Speichern verschlüsselt. Angenommen, jemand im Internet kann Ihren Datenverkehr abhören und Protokolle der Systemanforderungen führen. Ein Angreifer kann diese Informationen verwenden, um sie mit anderen Daten aus anderen Systemen abzugleichen.

5. Stellen Sie die HTTPS-Konnektivität bereit


Die meisten Browser benötigen derzeit HTTPS, um auf jeder Site zu funktionieren. Chrome zeigt Ihnen beispielsweise eine Warnung an, wenn die Site kein HTTPS verwendet. Die Informationssicherheitsabteilung kann die Transitverschlüsselung für die Kommunikation zwischen Diensten als Richtlinie verwenden. Um die Sicherheit der Transitverbindung im System zu gewährleisten, muss nicht nur die Anwendung auf Port 443 abgehört werden. Sie müssen auch die entsprechenden Zertifikate verwenden und HTTPS verwenden, um zu verhindern, dass Angreifer das Protokoll auf HTTP herabstufen.

Hier ist ein Codeausschnitt für eine Webanwendung, die das HTTPS-Protokoll bereitstellt und verwendet:

package main

import (
    "crypto/tls"
    "log"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
        w.Write([]byte("This is an example server.\n"))
    })
    cfg := &tls.Config{
        MinVersion:               tls.VersionTLS12,
        CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
        PreferServerCipherSuites: true,
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
        },
    }
    srv := &http.Server{
        Addr:         ":443",
        Handler:      mux,
        TLSConfig:    cfg,
        TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
    }
    log.Fatal(srv.ListenAndServeTLS("tls.crt", "tls.key"))
}


Beachten Sie, dass die Anwendung Port 443 überwacht. Die nächste Zeile ist die Zeile, die die HTTPS-Konfiguration bereitstellt:

w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")


Sie können den Servernamen in der TLS-Konfiguration auch folgendermaßen angeben:
config := &tls.Config{ServerName: "yourSiteOrServiceName"}


Es wird immer empfohlen, die Back-End-Verschlüsselung zu verwenden, auch wenn Ihre Webanwendung nur für die interne Kommunikation vorgesehen ist. Stellen Sie sich vor, ein Angreifer könnte aus irgendeinem Grund Ihren internen Datenverkehr abhören. Wann immer möglich, ist es immer am besten, die Messlatte für mögliche zukünftige Angreifer höher zu legen.

6. Achten Sie auf Fehler und Protokolle.


Last but not least Fehlerbehandlung und Protokollierung in Ihren Go-Anwendungen.

Um Produktionsprobleme erfolgreich zu beheben, müssen Sie Ihre Anwendungen ordnungsgemäß konfigurieren. Sie müssen die Fehler berücksichtigen, die Sie den Benutzern anzeigen. Sie möchten nicht, dass Benutzer wissen, was genau schief gelaufen ist. Angreifer können anhand dieser Informationen bestimmen, welche Dienste und Technologien Sie verwenden. Darüber hinaus sollten Sie daran denken, dass die Protokolle zwar wunderbar sind, aber irgendwo gespeichert werden. Und wenn die Protokolle in die falschen Hände geraten, können sie verwendet werden, um den bevorstehenden Angriff in das System einzubetten.

Das erste, was Sie lernen oder sich merken müssen, ist, dass es keine Ausnahmen gibt. Dies bedeutet, dass Sie Fehler anders behandeln müssen als in anderen Sprachen. Der Standard sieht folgendermaßen aus:

if err != nil {
    //  
}


Go bietet auch eine integrierte Bibliothek für die Arbeit mit Protokollen. Der einfachste Code sieht folgendermaßen aus:

package main

import (
	"log"
)

func main() {
	log.Print("Logging in Go!")
}


Es gibt jedoch Bibliotheken von Drittanbietern zum Verwalten von Protokollen. Einige davon sind logrus, glogund loggo. Hier ist ein kleiner Codeausschnitt mit logrus:

package main

import (
	"os"

	log "github.com/sirupsen/logrus"
)

func main() {
	file, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	log.SetOutput(file)
	log.SetFormatter(&log.JSONFormatter{})
	log.SetLevel(log.WarnLevel)

	log.WithFields(log.Fields{
		"animal": "walrus",
		"size":   10,
	}).Info("A group of walrus emerges from the ocean")
}


Stellen Sie schließlich sicher, dass Sie alle vorherigen Empfehlungen anwenden, z. B. die Verschlüsselung und Bereinigung der Daten, die Sie in die Protokolle aufgenommen haben.

Es gibt immer Raum zum Wachsen


Diese Richtlinien sind das Minimum, das für Ihre Go-Anwendungen spezifisch sein sollte. Wenn Ihre Anwendung jedoch ein Befehlszeilentool ist, benötigen Sie keine Verschlüsselungsmethoden für die Übertragung. Der Rest der Sicherheitstipps gilt jedoch für fast alle Arten von Anwendungen. Wenn Sie mehr wissen möchten, gibt es ein Buch von OWASP speziell für Go , das einige Themen behandelt. Es gibt auch ein Repository mit Links zu Frameworks, Bibliotheken und anderen Sicherheitstools in Go.

Denken Sie daran, dass Sie die Sicherheit Ihrer Anwendung jederzeit erhöhen können, unabhängig davon, was Sie am Ende tun. Angreifer werden immer neue Wege finden, um Schwachstellen auszunutzen. Versuchen Sie daher, ständig an der Sicherheit Ihrer Anwendung zu arbeiten.


. — , , , .NET, Node.js Java, Docker.

.

All Articles