РАЗБОР Статья 

Программирование. Кибербезопасность + Go = ❤️

szybnev
szybnev Newbie · 102 сообщений
Подписаться
7,9 тыс.
Режим чтения
Всем привет! Подготовил для вас материал по топу библиотек на Golang, которые необходимы вам при безопасной разработке приложений. Топ будет составлен лично по моему мнению, а я не являюсь сеньором-помидором Go разработчиком, так что не кидайтесь гнилыми тапками.

banner.jpg

[prebreak][/prebreak]​

1. Lego

lego.png


Данная библиотека выполняет функцию клиента Let's Encrypt'а и библиотеки ACME.

Возможности библиотеки:

  • ACME v2 RFC 8555
  • Регистрация с помощью центра сертификации
  • Получение сертификатов, как с нуля, так и с помощью существующего CSR
  • Перевыпуск сертификата
  • Отозвать сертификат:
    • Надежная реализация всех задач ACME
    • HTTP (http-01)
    • DNS (dns-01)
    • TLS (tls-alpn-01)
  • Поддержка сертификата SAN
  • Поставляется с несколькими дополнительными провайдерами DNS
  • Custom challenge solvers
  • Объединение сертификатов
  • Вспомогательная функция OCSP
Установка:
  • Из исполняемого файла
  • Docker
    • Bash:
      docker run goacme/lego -h
  • Пакетные менеджеры
    • Arch Linux -
      Bash:
      pacman -S lego
    • ArchLinux (AUR) -
      Bash:
      yay -S lego-bin
    • Debian -
      Bash:
      sudo apt install -y lego
  • Из сорцов
    • Bash:
      go install github.com/go-acme/lego/v4/cmd/lego@latest
    • Bash:
      git clone git@github.com:go-acme/lego.git
      cd lego
      make        # tests + doc + build
      make build  # only build

Данная библиотека имеет 2 варианта использования:​

1. CLI

Далее я расскажу вам, как использовать Lego для выпуска сертификатов:

Использовать встроенный веб-сервер
Bash:
lego --email="you@example.com" --domains="example.com" --http run

Вы найдете ваш сертификат в текущей рабочей директории, в папке .lego
Bash:
$ ls -1 ./.lego/certificates
example.com.crt
example.com.issuer.crt
example.com.json
example.com.key
[maybe more files for different domains...]

Разбор значений файлов:
  • example.com.crt - сертификат сервера (включая сертификат УЦ)
  • example.com.key - закрытый ключ, необходимый для сертификата сервера
  • example.com.issuer.crt - сертификат удостоверяющего центра
  • example.com.json - содержит некоторую метаинформацию в кодировке JSON

Использовать DNS провайдеров
Если вы не можете использовать веб сервер, то у вас есть возможность использовать DNS провайдеров. В Lego поддерживается достаточно большое количество DNS провайдеров и вы сами можете выбрать, каким из них пользоваться. Для примеру покажу, как использовать Cloudflare для вашего домена:
Bash:
CLOUDFLARE_EMAIL="you@example.com" \
CLOUDFLARE_API_KEY="yourprivatecloudflareapikey" \
lego --email "you@example.com" --dns cloudflare --domains "example.org" run

Использовать кастомный запрос на подпись сертификата
Первый шаг в процессе получения сертификатов включает в себя создание запроса на подписание. Этот CSR содержит различную информацию, включая имя (имена) домена и открытый ключ. По умолчанию lego скроет от вас этот шаг, но если у вас уже есть CSR, вы можете легко использовать его повторно:
Bash:
lego --email="you@example.com" --http --csr="/path/to/csr.pem" run
Lego сделает вывод о доменах, подлежащих проверке, на основе содержимого CSR, поэтому убедитесь, что общее имя CSR и необязательные SubjectAltNames установлены правильно.

Использовать уже существующий веб сервер
Если у вас уже есть работающий веб сервер на 80 порту, вам нужно добавить --http.webroot к аргументу --http. Это действие просто записывает токен вызова http-01 в указанный каталог в папку .well-known/acme-challenge и не запускает сервер. Для завершения проверки, директория должна быть / и доступна публично. Далее Lego запишет файл токенов с ключом авторизации HTTP-01 challenge в <webroot>/.well-known/acme-challenge/. Для этого выполните следующую команду:
Bash:
lego --accept-tos --email you@example.com --http --http.webroot /path/to/webroot --domains example.com run

Использовать скрипты
Вы можете легко подключиться к процессу получения сертификата, указав путь к скрипту:
Bash:
lego --email="you@example.com" --domains="example.com" --http run --run-hook="./myscript.sh"
И давайте объясню используемые переменные:
  • LEGO_ACCOUNT_EMAIL - электронная почта аккаунта
  • LEGO_CERT_DOMAIN - основной домен сертификата
  • LEGO_CERT_PATH - путь к сертификату
  • LEGO_CERT_KEY_PATH - путь к ключу сертификата

Теперь я вам расскажу вам как пользоваться ей для обновления сертификатов:

Использовать встроенный веб сервер
По умолчанию и в соответствии с классической практикой сертификат обновляется только в том случае, если срок его действия истекает менее чем через 30 дней.
Bash:
lego --email="you@example.com" --domains="example.com" --http renew

Если сертификат нужно перевыпустить ранее, вы можете указать количество дней за сколько выпустить его.
Bash:
lego --email="you@example.com" --domains="example.com" --http renew --days 45

Использовать DNS провайдера
Ранее я уже освещал о возможностях Lego в этом направлении, если что-то не понятно, то советую перечитать информацию выше)
Bash:
CLOUDFLARE_EMAIL="you@example.com" \
CLOUDFLARE_API_KEY="yourprivatecloudflareapikey" \
lego --email "you@example.com" --dns cloudflare --domains "example.org" renew

Использовать скрипты
Bash:
lego --email="you@example.com" --domains="example.com" --http renew --renew-hook="./myscript.sh"

Автоматический перевыпуск сертификата:
Очень заманчиво создать таск в cron (или таймер systemd) для автоматического обновления всех ваших сертификатов.
При этом следует учитывать, что некоторые настройки cron по умолчанию будут создавать ощутимую нагрузку на инфраструктуру провайдера ACME. В частности, задания @daily запускаются в полночь.

Пример оптимизированного таска для cron
Bash:
# avoid:
#@daily      /usr/bin/lego ... renew
#@midnight   /usr/bin/lego ... renew
#0 0 * * *   /usr/bin/lego ... renew

# instead, use a randomly chosen time:
35 3 * * *  /usr/bin/lego ... renew

Если вы используете systemd, то вот пример конфиг файла для вас:
Bash:
[Unit]
Description=Renew certificates

[Timer]
Persistent=true
# avoid:
#OnCalendar=*-*-* 00:00:00
#OnCalendar=daily

# instead, use a randomly chosen time:
OnCalendar=*-*-* 3:35
# add extra delay, here up to 1 hour:
RandomizedDelaySec=1h

[Install]
WantedBy=timers.target

2. Второй вариант использования Lego, напрямую как библиотеки

Правильный, но неполный пример использования пакета acme:

Код:
package main

import (
    "crypto"
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "fmt"
    "log"

    "github.com/go-acme/lego/v4/certcrypto"
    "github.com/go-acme/lego/v4/certificate"
    "github.com/go-acme/lego/v4/challenge/http01"
    "github.com/go-acme/lego/v4/challenge/tlsalpn01"
    "github.com/go-acme/lego/v4/lego"
    "github.com/go-acme/lego/v4/registration"
)

// You'll need a user or account type that implements acme.User
type MyUser struct {
    Email        string
    Registration *registration.Resource
    key          crypto.PrivateKey
}

func (u *MyUser) GetEmail() string {
    return u.Email
}
func (u MyUser) GetRegistration() *registration.Resource {
    return u.Registration
}
func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
    return u.key
}

func main() {

    // Create a user. New accounts need an email and private key to start.
    privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    if err != nil {
        log.Fatal(err)
    }

    myUser := MyUser{
        Email: "you@yours.com",
        key:   privateKey,
    }

    config := lego.NewConfig(&myUser)

    // This CA URL is configured for a local dev instance of Boulder running in Docker in a VM.
    config.CADirURL = "http://192.168.99.100:4000/directory"
    config.Certificate.KeyType = certcrypto.RSA2048

    // A client facilitates communication with the CA server.
    client, err := lego.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

    // We specify an HTTP port of 5002 and an TLS port of 5001 on all interfaces
    // because we aren't running as root and can't bind a listener to port 80 and 443
    // (used later when we attempt to pass challenges). Keep in mind that you still
    // need to proxy challenge traffic to port 5002 and 5001.
    err = client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "5002"))
    if err != nil {
        log.Fatal(err)
    }
    err = client.Challenge.SetTLSALPN01Provider(tlsalpn01.NewProviderServer("", "5001"))
    if err != nil {
        log.Fatal(err)
    }

    // New users will need to register
    reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
    if err != nil {
        log.Fatal(err)
    }
    myUser.Registration = reg

    request := certificate.ObtainRequest{
        Domains: []string{"mydomain.com"},
        Bundle:  true,
    }
    certificates, err := client.Certificate.Obtain(request)
    if err != nil {
        log.Fatal(err)
    }

    // Each certificate comes back with the cert bytes, the bytes of the client's
    // private key, and a certificate URL. SAVE THESE TO DISK.
    fmt.Printf("%#v\n", certificates)

    // ... all done.
}

Далее описывать функции библиотеки = переписать документацию. Так что приглашаю самим ознакомиться с ней.


2. zap

zap_logger.jpg

Обратите внимание, что zap поддерживает только две последние версии Go.
Zap - сверхбыстрое, структурированное, уровневое логгирование в Go

Установка​

Bash:
go get -u go.uber.org/zap

Использование​

В ситуациях, когда производительность важна, но не критична, используйте SugaredLogger. Он в 4-10 раз быстрее других пакетов структурированного протоколирования и включает в себя как структурированный, так и printf-стиль API.
Код:
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
  // Structured context as loosely typed key-value pairs.
  "url", url,
  "attempt", 3,
  "backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)

Если важны производительность и безопасность типов, используйте Logger. Он даже быстрее, чем SugaredLogger, и выделяет гораздо меньше ресурсов, но поддерживает только структурированное логгирование.
Код:
logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
  // Structured context as strongly typed Field values.
  zap.String("url", url),
  zap.Int("attempt", 3),
  zap.Duration("backoff", time.Second),
)

Для приложений, которые ведут журнал realtime, сериализация на основе отражения и форматирование строк непомерно дороги - они сильно нагружают процессор и делают много небольших выделений. Другими словами, использование encoding/json и fmt.Fprintf для регистрации тонн interface{}s делает ваше приложение непростительно медленным.
Zap использует другой подход. Он включает кодировщик JSON без отражений, с нулевым распределением, а базовый логгер стремится избегать накладных расходов на сериализацию и выделения, где это возможно. Создавая на этой основе высокоуровневый SugaredLogger, zap позволяет пользователям выбирать, когда им нужно считать каждое выделение, а когда они предпочитают более привычный, свободно типизированный API.

По оценкам собственного пакета бенчмарков, zap не только более производителен, чем аналогичные пакеты структурированного логгирования, но и быстрее, чем стандартная библиотека.
1683289418356.png


3. gosec

gosec.png


Данная библиотека проверяет исходный код на наличие проблем безопасности путем сканирования Go AST (Abstract Syntax Tree).

Установка порадует DevSecOps


CI установка

Bash:
curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(go env GOPATH)/bin vX.Y.Z

curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s vX.Y.Z

# для Alpine Linux, где по умолчанию нет curl
wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s vX.Y.Z

gosec --help

GitHub Action

Git:
name: Run Gosec
on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
jobs:
  tests:
    runs-on: ubuntu-latest
    env:
      GO111MODULE: on
    steps:
      - name: Checkout Source
        uses: actions/checkout@v3
      - name: Run Gosec Security Scanner
        uses: securego/gosec@master
        with:
          args: ./...

Локальная установка

Go 1.16+​

Код:
go install github.com/securego/gosec/v2/cmd/gosec@latest

Go version < 1.16​

Код:
go get -u github.com/securego/gosec/v2/cmd/gosec

Использование

Gosec может быть настроен на выполнение только групп правил, исключение определенных путей к файлам и создание отчетов в различных форматах. По умолчанию все правила будут выполняться по предоставленным входным файлам. Для рекурсивного сканирования из текущего каталога в качестве входного аргумента можно указать ./...

Доступные правила аудита

  • G101: Look for hard coded credentials
  • G102: Bind to all interfaces
  • G103: Audit the use of unsafe block
  • G104: Audit errors not checked
  • G106: Audit the use of ssh.InsecureIgnoreHostKey
  • G107: Url provided to HTTP request as taint input
  • G108: Profiling endpoint automatically exposed on /debug/pprof
  • G109: Potential Integer overflow made by strconv.Atoi result conversion to int16/32
  • G110: Potential DoS vulnerability via decompression bomb
  • G111: Potential directory traversal
  • G112: Potential slowloris attack
  • G113: Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772)
  • G114: Use of net/http serve function that has no support for setting timeouts
  • G201: SQL query construction using format string
  • G202: SQL query construction using string concatenation
  • G203: Use of unescaped data in HTML templates
  • G204: Audit use of command execution
  • G301: Poor file permissions used when creating a directory
  • G302: Poor file permissions used with chmod
  • G303: Creating tempfile using a predictable path
  • G304: File path provided as taint input
  • G305: File traversal when extracting zip/tar archive
  • G306: Poor file permissions used when writing to a new file
  • G401: Detect the usage of DES, RC4, MD5 or SHA1
  • G402: Look for bad TLS connection settings
  • G403: Ensure minimum RSA key length of 2048 bits
  • G404: Insecure random number source (rand)
  • G501: Import blocklist: crypto/md5
  • G502: Import blocklist: crypto/des
  • G503: Import blocklist: crypto/rc4
  • G504: Import blocklist: net/http/cgi
  • G505: Import blocklist: crypto/sha1
  • G601: Implicit memory aliasing of items from a range statement

Выбор правил аудита

По умолчанию gosec будет выполнять все правила по указанным путям к файлам. Однако можно выбрать группы правил для запуска с помощью флага -include= или указать группы правил для явного исключения с помощью флага -exclude=.
Bash:
# Запуситить конкретные правила
$ gosec -include=G101,G203,G401 ./...

# Использовать все правила, кроме G303
$ gosec -exclude=G303 ./...

CWE Mapping

Это уже порадует безопасников, т.к. каждая проблема соотноситься с CWE (Common Weakness Enumeration), которая описывает уязвимость.

Исключения:

Исключение тестовых файлов и папок при аудите

gosec будет игнорировать тестовые файлы всех пакетов и любых зависимостей в вашем каталоге.
Сканирование тестовых файлов может быть включено с помощью следующего флага:
Код:
gosec -tests ./...
Также можно исключить дополнительные папки следующим образом:
Код:
gosec -exclude-dir=rules -exclude-dir=cmd ./...

Исключение сгенерированных файлов

gosec может игнорировать сгенерированные go-файлы с комментарием сгенерированного кода по умолчанию.

// Code generated by some generator DO NOT EDIT.
Код:
gosec -exclude-generated ./...

Сохранение результатов

В настоящее время gosec поддерживает форматы вывода text, json, yaml, csv, sonarqube, JUnit XML, html и golint. По умолчанию результаты выводятся на stdout(т.е. в консоль), но также могут быть записаны в файл. Формат вывода контролируется флагом -fmt, а имя файла устанавливается флагом -out следующим образом:
Bash:
# Запись результатов в json в файл results.json
$ gosec -fmt=json -out=results.json *.go
Также вы можете сохранить результат и в файлы, и вывести в консоль:
Bash:
$ gosec -fmt=json -out=results.json -stdout *.go

4. Hydra

hydra_oauth.png


Ory Hydra - это усиленный, сертифицированный OpenID OAuth 2.0 сервер и провайдер OpenID Connect, оптимизированный для низкой задержки, высокой пропускной способности и низкого потребления ресурсов. Ory Hydra не является провайдером идентификации (регистрация пользователя, вход пользователя, поток сброса пароля), а подключается к существующему провайдеру идентификации через приложение для входа и согласия.
Ory Hydra может использовать Ory Kratos в качестве сервера идентификации.

Ory Hydra - это серверная реализация системы авторизации OAuth 2.0 и OpenID Connect Core 1.0. Существующие реализации OAuth2 обычно поставляются в виде библиотек или SDK, таких как node-oauth2-server или Ory Fosite, или в виде полнофункциональных решений идентификации с управлением пользователями и пользовательскими интерфейсами, таких как Keycloak. Внедрение и использование OAuth2 без понимания всей спецификации является сложной задачей и чревато ошибками, даже если используются SDK. Основная цель Ory Hydra - сделать OAuth 2.0 и OpenID Connect 1.0 более доступными.
Самых крупные компании, использующие Hydra вы можете увидеть здесь.

Начнём с установки. Есть 2 стула:


  1. Docker - установка займет 5 минут. Гайд тут.
  2. Для настоящих мужчин

Bash:
# Linux
bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -b . ory
sudo mv ./ory /usr/local/bin/

# MacOS
brew install ory/tap/cli

Далее создаем проект:
Код:
ory create project --name "Ory Hydra 2.0 Example"
project_id="{set to the id from output}"

OAuth 2.0 Client Credentials / Machine-to-Machine

Создайте клиент OAuth 2.0 и запустите процесс OAuth 2.0 Client Credentials:
Bash:
ory create oauth2-client --project $project_id \
    --name "Client Credentials Demo" \
    --grant-type client_credentials
client_id="{set to client id from output}"
client_secret="{set to client secret from output}"

ory perform client-credentials --client-id=$client_id --client-secret=$client_secret --project $project_id
access_token="{set to access token from output}"

ory introspect token $access_token --project $project_id

OAuth 2.0 Authorize Code + OpenID Connect

Bash:
ory create oauth2-client --project $project_id \
    --name "Authorize Code with OpenID Connect Demo" \
    --grant-type authorization_code,refresh_token \
    --response-type code \
    --redirect-uri http://127.0.0.1:4446/callback
code_client_id="{set to client id from output}"
code_client_secret="{set to client secret from output}"

ory perform authorization-code \
    --project $project_id \
    --client-id $code_client_id \
    --client-secret $code_client_secret
code_access_token="{set to access token from output}"

ory introspect token $code_access_token --project $project_id

5. TFSec

tfsec.png


tfsec использует статический анализ кода terraform для выявления возможных мисконфигов.

Начнем с установки

Установка с помощью brew/linuxbrew
Код:
brew install tfsec

Установка с помощью Chocolatey
Код:
choco install tfsec

Установка с помощью Scoop
Код:
scoop install tfsec

Установка в Linux:
Код:
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash

Также вы можете скачать бинарь с releases page.

Также вы можете установить из исходников с помощью Go:
Код:
go install github.com/aquasecurity/tfsec/cmd/tfsec@latest

Использование

Тут довольно всё просто) tfsec будет сканировать указанный каталог. Если каталог не указан, будет использоваться текущий рабочий каталог.
Bash:
tfsec .

Использовать через Docker

В качестве альтернативы установке и запуску tfsec на вашей системе, вы можете запустить tfsec в контейнере Docker:

Название образаОбразОписание
aquasec/tfsecalpineОбычный tfsec образ
aquasec/tfsec-alpinealpineТочно так же, как aquasec/tfsec, но для тех, кто любит ясность.
aquasec/tfsec-cialpinetfsec без entrypoint- полезно для сборок CI, где вы хотите переопределить команду
aquasec/tfsec-scratchscratchОбраз, созданный с нуля - ничего лишнего, просто работает tfsec

Bash:
docker run --rm -it -v "$(pwd):/src" aquasec/tfsec /src

Использование через Github Actions

Git:
name: tfsec-pr-commenter
on:
  pull_request:
jobs:
  tfsec:
    name: tfsec PR commenter
    runs-on: ubuntu-latest

    permissions:
      contents: read
      pull-requests: write

    steps:
      - name: Clone repo
        uses: actions/checkout@master
      - name: tfsec
        uses: aquasecurity/tfsec-pr-commenter-action@v1.2.0
        with:
          github_token: ${{ github.token }}


Я надеюсь вам будет полезна эта статья. Если вас больше интересного контента от меня, то предлагаю подписаться на мой канал в telegram Дневник Безопасника 🛡
Полезно · 9

Комментарии

2
Спасибо за тулы, будет полезно людям которые только начинают в golang и имеют опыт в иб
 
  • Нравится
Реакции: szybnev
1
Спасибо за тулы, будет полезно людям которые только начинают в golang и имеют опыт в иб
Спасибо за коммент) Если интересно, то могу сделать похожие статьи про другие языки.
 
  • Нравится
Реакции: katok_
1