Created
March 14, 2026 15:13
-
-
Save mohashari/524e43fe54bb5ac5aff25ce58adf5b1d to your computer and use it in GitHub Desktop.
Code snippets — Api Security Owasp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: Trust third-party data blindly | |
| resp := stripe.GetPayment(paymentID) | |
| db.Save(Payment{Amount: resp.Amount, Currency: resp.Currency}) | |
| // GOOD: Validate before using | |
| resp := stripe.GetPayment(paymentID) | |
| if resp.Amount <= 0 || resp.Amount > MaxPaymentAmount { | |
| return errors.New("invalid amount from payment provider") | |
| } | |
| if !validCurrencies[resp.Currency] { | |
| return errors.New("invalid currency from payment provider") | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: Sequential, predictable IDs as tokens | |
| token := fmt.Sprintf("token_%d", userID) | |
| // BAD: Weak reset token | |
| token := fmt.Sprintf("%d", time.Now().Unix()) | |
| // GOOD: Cryptographically secure random token | |
| func generateToken() string { | |
| bytes := make([]byte, 32) | |
| rand.Read(bytes) | |
| return hex.EncodeToString(bytes) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: Returns entire user object including internal fields | |
| type User struct { | |
| ID int `json:"id"` | |
| Email string `json:"email"` | |
| PasswordHash string `json:"password_hash"` // ← Never expose! | |
| IsAdmin bool `json:"is_admin"` // ← Sensitive | |
| InternalNotes string `json:"internal_notes"` // ← Internal only | |
| } | |
| // GOOD: Separate response types | |
| type UserResponse struct { | |
| ID int `json:"id"` | |
| Email string `json:"email"` | |
| Name string `json:"name"` | |
| } | |
| func toUserResponse(user *User) UserResponse { | |
| return UserResponse{ID: user.ID, Email: user.Email, Name: user.Name} | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: Blindly bind all JSON fields (attacker can set is_admin=true) | |
| json.NewDecoder(r.Body).Decode(&user) | |
| db.Save(user) | |
| // GOOD: Only accept specific fields | |
| type UpdateProfileRequest struct { | |
| Name string `json:"name"` | |
| Email string `json:"email"` | |
| // No is_admin field — attackers can't set it | |
| } | |
| var req UpdateProfileRequest | |
| json.NewDecoder(r.Body).Decode(&req) | |
| user.Name = req.Name | |
| user.Email = req.Email | |
| db.Save(user) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Limits middleware | |
| func LimitsMiddleware(next http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| // Limit request body size (default is unlimited!) | |
| r.Body = http.MaxBytesReader(w, r.Body, 1*1024*1024) // 1MB max | |
| next.ServeHTTP(w, r) | |
| }) | |
| } | |
| // Pagination limits | |
| func ListOrders(w http.ResponseWriter, r *http.Request) { | |
| limit := parseIntParam(r, "limit", 20) | |
| if limit > 100 { | |
| limit = 100 // Cap at 100 regardless of what client requests | |
| } | |
| // ... | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: Any authenticated user can access admin endpoints | |
| router.DELETE("/api/users/{id}", deleteUserHandler) | |
| // GOOD: Role-based access control middleware | |
| router.With(RequireRole("admin")).DELETE("/api/users/{id}", deleteUserHandler) | |
| func RequireRole(role string) func(http.Handler) http.Handler { | |
| return func(next http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| user := r.Context().Value("user").(*User) | |
| if !user.HasRole(role) { | |
| http.Error(w, "Forbidden", 403) | |
| return | |
| } | |
| next.ServeHTTP(w, r) | |
| }) | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Add CAPTCHA verification for sensitive flows | |
| func Register(w http.ResponseWriter, r *http.Request) { | |
| var req RegisterRequest | |
| json.NewDecoder(r.Body).Decode(&req) | |
| // Verify CAPTCHA | |
| if !captcha.Verify(req.CaptchaToken) { | |
| http.Error(w, "Invalid CAPTCHA", 400) | |
| return | |
| } | |
| // Rate limit by IP | |
| if !ipRateLimiter.Allow(r.RemoteAddr) { | |
| http.Error(w, "Too Many Requests", 429) | |
| return | |
| } | |
| createUser(req) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // BAD: Fetches any URL the user provides | |
| func FetchPreview(url string) (string, error) { | |
| resp, err := http.Get(url) | |
| // Attacker sends: http://169.254.169.254/latest/meta-data/ (AWS metadata!) | |
| // ... | |
| } | |
| // GOOD: Validate and allowlist URLs | |
| func FetchPreview(rawURL string) (string, error) { | |
| parsed, err := url.Parse(rawURL) | |
| if err != nil { | |
| return "", errors.New("invalid URL") | |
| } | |
| // Only allow HTTPS | |
| if parsed.Scheme != "https" { | |
| return "", errors.New("only HTTPS URLs allowed") | |
| } | |
| // Block private IP ranges | |
| ips, _ := net.LookupHost(parsed.Hostname()) | |
| for _, ip := range ips { | |
| if isPrivateIP(net.ParseIP(ip)) { | |
| return "", errors.New("private IPs not allowed") | |
| } | |
| } | |
| resp, err := http.Get(rawURL) | |
| // ... | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| func SecurityHeadersMiddleware(next http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| w.Header().Set("X-Content-Type-Options", "nosniff") | |
| w.Header().Set("X-Frame-Options", "DENY") | |
| w.Header().Set("X-XSS-Protection", "1; mode=block") | |
| w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") | |
| w.Header().Set("Content-Security-Policy", "default-src 'self'") | |
| next.ServeHTTP(w, r) | |
| }) | |
| } | |
| // Never expose internal errors | |
| func errorResponse(w http.ResponseWriter, err error, statusCode int) { | |
| log.Printf("Internal error: %v", err) // Log full error internally | |
| // Return generic message to client | |
| http.Error(w, "An internal error occurred", statusCode) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| func GetOrder(w http.ResponseWriter, r *http.Request) { | |
| orderID := chi.URLParam(r, "id") | |
| currentUser := r.Context().Value("user").(*User) | |
| order, err := db.GetOrder(ctx, orderID) | |
| if err != nil { | |
| http.Error(w, "Not Found", 404) | |
| return | |
| } | |
| // CRITICAL: Verify ownership | |
| if order.UserID != currentUser.ID { | |
| http.Error(w, "Forbidden", 403) | |
| return | |
| } | |
| json.NewEncoder(w).Encode(order) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Attacker changes user ID from their ID to victim's ID | |
| GET /api/orders/99999 ← victim's order ID | |
| Authorization: Bearer attacker_token |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment