Golang : reCAPTCHA example




For this tutorial we will explore how to implement reCAPTCHA with Golang. If you are running website with lots of user generated content, fighting spammers can be tedious and endless battle. To mitigate this problem, we can deploy reCAPTCHA service to minimize spammers activities on your website.

reCAPTCHA works by testing the visitor to see if they are a spambot or human. The tests deployed by reCAPTCHA are difficult for spambots to pass and will discourage human spammers from spamming your website repeatedly.

a sample of reCAPTCHA test

a sample of reCAPTCHA test

1. Register a reCAPTCHA account.


First, you need to register a reCAPTCHA account to create new site and secret keys for your website. Go to http://www.google.com/recaptcha/ to get the keys.

2. Bind reCAPTCHA to your form.


Next, we will bind the reCAPTCHA to a signup form. The code example below will be annotated to show where to place the reCAPTCHA codes.

 package main

 import (
 "encoding/json"
 "fmt"
 "io/ioutil"
 "net/http"
 "net/url"
 "time"
 )

 type JSONAPIResponse struct {
 Success bool `json:"success"`
 ChallengeTS time.Time `json:"challenge_ts"` // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
 Hostname string `json:"hostname"` // the hostname of the site where the reCAPTCHA was solved
 ErrorCodes  []int `json:"error-codes"`  //optional
 }

 func RecaptchaForm(w http.ResponseWriter, r *http.Request) {
 html := `<!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="UTF-8">
 <title>Golang reCAPTCHA Signup Form</title>
 <script src='https://www.google.com/recaptcha/api.js'></script>
 </head>
 <body>
 <h1>Golang reCAPTCHA Signup Form</h1>
 <form method="POST" action="/signup">
 Username : <input type="text" name="username">
 <br>
 Password : <input type="password" name="password">
 <br>
 <div class="g-recaptcha" data-sitekey="[REPLACE WITH YOUR DATA KEY]"></div>
 <br>
 <input type="submit" value="Submit">
 </form>
 </body>
 </html>`

 w.Write([]byte(html))
 }

 func Signup(w http.ResponseWriter, r *http.Request) {

 if r.Method == "POST" {
 fmt.Println("username : ", r.FormValue("username"))
 fmt.Println("password : ", r.FormValue("password"))

 response := r.FormValue("g-recaptcha-response")
 fmt.Println("g-recaptcha-response : ", response)

 // did we get a proper recaptcha response? if null, redirect back to sigup page
 if response == "" {
 // user press submit button without passing reCAPTCHA test
 // abort
 http.Redirect(w, r, "/", 301)
 return // return control to stop execution, otherwise it will continue
 }

 // this is server side validation example
 // it is optional, but no harm adding this on your signup verification process.


 // if you are running this example on localhost
 // get your own IP address from https://whatismyipaddress.com/
 // and assign it to the variable ip

 remoteip := "[REPLACE WITH YOUR IP ADDRESS IF ON LOCALHOST OR UNCOMMENT SPLITHOST BELOW]"

 // get end user's IP address
 //remoteip, _, _ := net.SplitHostPort(r.RemoteAddr)

 fmt.Println("remote ip : ", remoteip)

 // to verify if the recaptcha is REAL. we must send
 // secret + response + remoteip(optional) to postURL

 secret := "[REPLACE WITH YOUR SECRET KEY]"
 postURL := "https://www.google.com/recaptcha/api/siteverify"

 postStr := url.Values{"secret": {secret}, "response": {response}, "remoteip": {remoteip}}

 responsePost, err := http.PostForm(postURL, postStr)

 if err != nil {
 fmt.Println(err)
 return
 }

 defer responsePost.Body.Close()
 body, err := ioutil.ReadAll(responsePost.Body)

 if err != nil {
 fmt.Println(err)
 return
 }

 // this part is for server side verification
 var APIResp JSONAPIResponse

 json.Unmarshal(body, &APIResp)
 fmt.Println(APIResp)

 // see https://www.socketloop.com/tutorials/golang-output-or-print-out-json-stream-encoded-data

 w.Header().Set("Content-Type", "application/json")
 w.Write([]byte(body))

 //once everything is verified, you can proceed to save the user data into your database
 }
 }

 func main() {
 mux := http.NewServeMux()
 mux.HandleFunc("/", RecaptchaForm)
 mux.HandleFunc("/signup", Signup)

 http.ListenAndServe(":8080", mux)
 }

Run this program and point your browser to localhost:8080 or your own website configuration.

IF everything goes smoothly, you should see a prompt such as this

a signup form binded to reCAPTCHA

a signup form binded to reCAPTCHA

and upon successful verification, the JSON reply from reCAPTCHA API will appear on the web browser:

 {
 "success": true,
 "challenge_ts": "2016-06-28T08:46:50Z",
 "hostname": "localhost"
 }

and on the terminal:

username : asd

password : asd

g-recaptcha-response : 03AHJVuuLBKWMkViN8MDY8qV7A9nLVdSlhVZEGkqq7CqynW1....

remote ip : 121.122.88.120

{true 2016-06-28 08:46:50 +0000 UTC localhost []}

References:

https://developers.google.com/recaptcha/docs/verify





By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement