Irbisa · Cheatsheet

Networking & Security for Backend

TCP and the OSI model, DNS, TLS, HTTP/3 and QUIC, load balancers and proxies, WebSockets, CORS, password hashing, OAuth 2.0 and JWT, SSRF, mTLS

Middle Developer · 19 questions

  1. 01

    What are the layers of the OSI and TCP/IP models, and at which layer do IP, TCP, TLS, HTTP and a load balancer work?

    OSI has seven layers: physical, data link, network, transport, session, presentation, application.

  2. 02

    What happens, step by step, between typing https://example.com/orders into a browser and the first byte of the response?

    The browser resolves example.com through DNS, opens a TCP connection to port 443, runs a TLS handshake and sends GET /orders over it.

  3. 03

    How does HTTPS differ from HTTP, what does a TLS handshake do, and when would you pick UDP over TCP?

    HTTPS is HTTP over TLS: the handshake agrees on a cipher and verifies the server's certificate, then both sides encrypt with a session key, so traffic is private and tamper-evident.

  4. 04

    What is CORS, which requests trigger a preflight OPTIONS, and why does CORS not protect an API from curl or another server?

    CORS is how a server tells the browser which other origins may read its responses, and the browser is what enforces it.

  5. 05

    How does a WebSocket connection start from an HTTP request, and what must proxies and load balancers in front of a Go service support to keep it open?

    The client sends an ordinary GET with Upgrade: websocket and Connection: Upgrade; the server answers 101 Switching Protocols, and from then on the same TCP connection carries WebSocket frames both ways.

    // Registered as mux.HandleFunc("GET /ws", chat).func chat(w http.ResponseWriter, r *http.Request) {	// Checks the Upgrade headers and Origin, then answers 101 Switching Protocols.	c, err := websocket.Accept(w, r, &websocket.AcceptOptions{		OriginPatterns: []string{"app.example.com"}, // browsers send Origin; CORS does not apply here	})…
  6. 06

    How does TCP open a connection with the three-way handshake and close it, and why does a busy client pile up sockets in TIME_WAIT?

    TCP opens with SYN, SYN-ACK, ACK, one round trip before any data, and closes with a FIN and an ACK in each direction.

  7. 07

    How does DNS resolution work, and why can a Go service keep sending traffic to an old IP for minutes after the record changes?

    A recursive resolver walks from the root to the TLD to the domain's authoritative servers, and every answer is cached for its TTL.

  8. 08

    How does a TLS client decide that a certificate really belongs to api.example.com, and what should you do instead of InsecureSkipVerify for a private CA?

    It builds a chain from the server's certificate through the intermediates to a root it already trusts, checks each certificate's validity dates, and checks that the hostname is in the leaf's Subject Alternative Names.

    // The billing API uses a certificate from the company CA, which is not in// the system pool, so calls fail with "certificate signed by unknown authority".func newBillingClient(companyCA []byte) (*http.Client, error) {	pool, err := x509.SystemCertPool()	if err != nil {		return nil, err…
  9. 09

    What does HTTP/3 over QUIC change compared with HTTP/2 over TCP (handshake, head-of-line blocking, connection migration), and does a Go API need it?

    HTTP/3 runs over QUIC, a transport on UDP with TLS 1.3 built in: one round trip to connect instead of TCP's plus TLS's, streams that do not stall each other when a packet is lost, and connections that survive a change of IP.

  10. 10

    What is the difference between an L4 and an L7 load balancer, and what can each one see and do with a request?

    An L4 balancer forwards TCP or UDP connections by IP and port without reading them, so it works for any protocol but balances whole connections.

  11. 11

    Forward proxy vs reverse proxy: what is the difference, and how does a Go service behind one get the client's real IP without trusting a spoofed X-Forwarded-For?

    A forward proxy acts for clients and reaches any server, like a corporate egress proxy; a reverse proxy stands in front of servers, like nginx, an ingress or a load balancer.

    // The address ranges of our own load balancers and ingress proxies.var trustedProxies = []netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")} func trusted(ip netip.Addr) bool {	return slices.ContainsFunc(trustedProxies, func(p netip.Prefix) bool { return p.Contains(ip) })}…
  12. 12

    How should a Go service store user passwords, why is SHA-256 the wrong tool, and what do bcrypt and argon2id from golang.org/x/crypto do differently?

    Store a slow, salted hash, never the password or a fast hash of it.

    // bcrypt: the salt and the cost travel inside the result, "$2a$12$<salt><hash>".func hashPassword(pw string) (string, error) {	h, err := bcrypt.GenerateFromPassword([]byte(pw), 12) // ErrPasswordTooLong past 72 bytes	return string(h), err}…
  13. 13

    JWT or server-side sessions: what are the trade-offs, where should a browser keep the token, and what is IDOR?

    A session is a random ID that points to state on the server, so you can revoke it at once; a JWT is a signed token checked without a lookup, so it scales without shared state but stays valid until it expires.

  14. 14

    Find the bug: a JWT minted by a test script two years ago still authenticates against production.

    var secret = []byte(os.Getenv("JWT_SECRET")) // userID authenticates every request to the orders API.func userID(raw string) (string, error) {	tok, err := jwt.Parse(raw, func(t *jwt.Token) (any, error) {		return secret, nil	})	if err != nil {		return "", err	}	return tok.Claims.GetSubject()}

    golang-jwt checks exp only when the token has one: the claim is optional by default, so the script's token, minted without exp, is valid forever.

  15. 15

    How does the OAuth 2.0 authorization code flow with PKCE work, and what does OpenID Connect add on top of OAuth?

    The app sends the user to the identity provider, which signs them in and redirects back with a one-time code; the backend exchanges the code, plus a PKCE verifier only it knows, for tokens.

    var conf = &oauth2.Config{	ClientID:     "orders-web",	ClientSecret: "from-the-secret-store", // a backend is a confidential client	RedirectURL:  "https://app.example.com/callback",	Scopes:       []string{oidc.ScopeOpenID, "email"},	Endpoint:     oauth2.Endpoint{AuthURL: "https://id.example.com/authorize", TokenURL: "https://id.example.com/token"},…
  16. 16

    This function checks a webhook's HMAC signature before the handler trusts the body. Which two security bugs does it have, and how do you fix them?

    // The provider sends X-Signature: hex(HMAC-SHA256(secret, body)).func verifyWebhook(r *http.Request, secret []byte) ([]byte, error) {	body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))	if err != nil {		return nil, err	}	mac := hmac.New(sha256.New, secret)	mac.Write(body)	want := hex.EncodeToString(mac.Sum(nil))	if r.Header.Get("X-Signature") != want {		return nil, errors.New("bad signature")	}	return body, nil}

    It compares the signatures with !=, which is not constant-time, so timing can leak how much of a forged signature is right; and it signs only the body, so a captured request can be replayed forever.

  17. 17

    Find the bug: a file download endpoint lets any user read /etc/passwd and the service's own config file.

    // filesDir is "/srv/app/uploads"; the config lives in /srv/app/config.yaml.// Registered as mux.HandleFunc("GET /download", download).func download(w http.ResponseWriter, r *http.Request) {	name := r.URL.Query().Get("name") // "report.pdf"	http.ServeFile(w, r, filepath.Join(filesDir, name))}

    The name from the query string goes straight into filepath.Join, which resolves ..: ?name=../../../etc/passwd becomes /etc/passwd, and ?name=../config.yaml the service's config.

  18. 18

    Your service fetches a user-supplied webhook URL. What is SSRF, and how do you block 169.254.169.254 and internal hosts, including through DNS rebinding?

    Server-side request forgery (SSRF) makes your server send requests the attacker cannot send directly: to the cloud metadata service, localhost admin ports or internal APIs.

    var cgnat = netip.MustParsePrefix("100.64.0.0/10") // carrier-grade NAT, not in IsPrivate // Control runs on every dial, after DNS, with the IP about to be connected,// so a rebinding answer or a redirect to 10.0.0.5 is checked as well.func publicOnly(network, address string, _ syscall.RawConn) error {	ap, err := netip.ParseAddrPort(address)…
  19. 19

    How does mutual TLS between two Go services work, and which tls.Config fields must each side set so that neither talks to an impostor?

    In mTLS the server also asks for a certificate, and each side verifies the other's chain against a private CA: the server sets ClientAuth: tls.RequireAndVerifyClientCert and ClientCAs, the client RootCAs, its own Certificates and ServerName.

    // Server: only callers with a certificate from our CA, and only the allowed ones.func serverTLS(cert tls.Certificate, clientCAs *x509.CertPool, allowed []string) *tls.Config {	return &tls.Config{		Certificates: []tls.Certificate{cert},		ClientAuth:   tls.RequireAndVerifyClientCert, // RequireAnyClientCert does not verify		ClientCAs:    clientCAs,…