/pub/go-strings-aleatorias.md


Secure Random Strings in Golang Using crypto/rand

· #golang #development #grupo-estudos-golang

Generating random strings is extremely useful. You need it in all sorts of places: creating keys for records in distributed databases without risking collisions, creating session IDs, generating passwords, and much more.

Simple as the task looks, there are a few interesting tricks to it. Computers aren’t actually good at creating truly random things. They create predictable things, which is not what you want when the goal is cryptography and security.

It would be disastrous, for example, if someone could guess a website’s session ID. Hijacking other users’ sessions would be trivial. The more unpredictable the key string, the better.

Fortunately, Go ships with a package for generating high-quality keys. In the example below, we use the crypto/rand package to generate a random 10-byte string. We then compute a sha1 hash of that string and convert the hash to hexadecimal for display.

package main

import (
    "crypto/rand"
    "crypto/sha1"
    "fmt"
)

func hash(b []byte) string {
    h := sha1.New()
    h.Write(b)
    sum := h.Sum(nil)
    armored := fmt.Sprintf("%x", sum)
    return armored
}

func randomString() (string, error) {
    b := make([]byte, 10)
    _, err := rand.Read(b)

    if err != nil {
        fmt.Printf("error: %v", err)
        return "", err
    }

    armored := hash(b)
    return armored, err
}

func main() {
    s, _ := randomString()
    fmt.Printf("random string: %s\n", armored)
}

Try it on the Golang Playground

This code covers most applications. The crypto/rand package generates high-quality random numbers, and 10 bytes is enough for almost anything. With a couple of simple tweaks, you can make even stronger strings: raise the number of bytes and switch to a more suitable hash type.

I often use sha256 with a 16-byte string, for instance. That gives you an astronomical number of possible combinations: 2^128, or 340 trillion trillion trillion of them.

The chance of an accidental collision — generating the same string twice in a system — is minuscule.

I often need longer strings. For those cases, I use the code below.

func randomStringWithLength(length int) (string, error) {
    const (
        charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    )
    lenCharset := byte(len(charset))
    b := make([]byte, length)
    rand.Read(b)
    for i := 0; i < length; i++ {
        b[i] = charset[b[i]%lenCharset]
    }
    return string(b), nil
}

Besides letting you pass the length of the output string, this lets you define the charset you want to use. In the example above I used a charset with uppercase letters, lowercase letters, and digits. You can add or remove characters and symbols as needed.

Another approach I use for random strings is generating a UUID v4 with the github.com/google/uuid package.

import "github.com/google/uuid"
.
.
.
ID := uuid.New().String()
fmt.Println(ID)

UUIDs are especially handy if you use PostgreSQL as your database. You can use a uuid column type, and PostgreSQL validates the input, refusing strings that don’t follow the UUID format. Beyond being an extra layer of protection against programming mistakes, it also helps prevent SQL injection attacks.

Nearly every system I’ve built has, at some point, turned into a distributed system. Using UUIDs as database indexes is practically mandatory in those cases.

See the full source code here.

Video explaining the code:

Cesar Gimenes


crg.eti.br · © 2026 Cesar Gimenes · CC BY 4.0 · github · pt