From db91ee8ce553be6952d90f2810833e82a9130c90 Mon Sep 17 00:00:00 2001 From: Yao Wei Date: Wed, 25 May 2016 11:01:04 +0800 Subject: [PATCH 1/3] Add remote IP for extra security --- recaptcha.go | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/recaptcha.go b/recaptcha.go index 7d61c9a..0d1a03e 100644 --- a/recaptcha.go +++ b/recaptcha.go @@ -19,16 +19,19 @@ package recaptcha import ( "encoding/json" "io/ioutil" + "net" "net/http" "net/url" + "strings" "time" ) // R type represents an object of Recaptcha and has public property Secret, // which is secret obtained from google recaptcha tool admin interface type R struct { - Secret string - lastError []string + Secret string + lastError []string + TrustXForwardedFor bool } // Struct for parsing json in google's response @@ -46,9 +49,11 @@ var postURL = "https://www.google.com/recaptcha/api/siteverify" func (r *R) Verify(req http.Request) bool { r.lastError = make([]string, 1) response := req.FormValue("g-recaptcha-response") + addr := r.findRemoteAddr(&req) client := &http.Client{Timeout: 20 * time.Second} + resp, err := client.PostForm(postURL, - url.Values{"secret": {r.Secret}, "response": {response}}) + url.Values{"secret": {r.Secret}, "response": {response}, "remoteip": {addr}}) if err != nil { r.lastError = append(r.lastError, err.Error()) return false @@ -75,3 +80,21 @@ func (r *R) Verify(req http.Request) bool { func (r R) LastError() []string { return r.lastError } + +// findRemoteAddr gets remote address +func (r *R) findRemoteAddr(req *http.Request) string { + addr := "" + + if r.TrustXForwardedFor { + addr = req.Header.Get("X-Forwarded-For") + } + + if addr == "" { + addr, _, _ = net.SplitHostPort(req.RemoteAddr) + } else { + addrs := strings.Split(addr, ",") + addr = strings.TrimSpace(addrs[len(addrs)-1]) + } + + return addr +} From 3cedc730580da63f6895f41b12a1e05f982621d0 Mon Sep 17 00:00:00 2001 From: Yao Wei Date: Wed, 25 May 2016 11:29:50 +0800 Subject: [PATCH 2/3] Make remoteip optional --- recaptcha.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/recaptcha.go b/recaptcha.go index 0d1a03e..bee159d 100644 --- a/recaptcha.go +++ b/recaptcha.go @@ -31,6 +31,7 @@ import ( type R struct { Secret string lastError []string + UseRemoteIP bool TrustXForwardedFor bool } @@ -49,11 +50,15 @@ var postURL = "https://www.google.com/recaptcha/api/siteverify" func (r *R) Verify(req http.Request) bool { r.lastError = make([]string, 1) response := req.FormValue("g-recaptcha-response") - addr := r.findRemoteAddr(&req) - client := &http.Client{Timeout: 20 * time.Second} + params := url.Values{"secret": {r.Secret}, "response": {response}} + + if r.UseRemoteIP { + addr := r.findRemoteAddr(&req) + params.Set("remoteip", addr) + } - resp, err := client.PostForm(postURL, - url.Values{"secret": {r.Secret}, "response": {response}, "remoteip": {addr}}) + client := &http.Client{Timeout: 20 * time.Second} + resp, err := client.PostForm(postURL, params) if err != nil { r.lastError = append(r.lastError, err.Error()) return false From 1a62da3baba8b3a1f745a10a722a917089f3a313 Mon Sep 17 00:00:00 2001 From: Yao Wei Date: Wed, 13 Jul 2016 18:30:57 +0800 Subject: [PATCH 3/3] docs: add documents for UseRemoteIP and TrustXForwardedFor --- recaptcha.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/recaptcha.go b/recaptcha.go index bee159d..6b7abaa 100644 --- a/recaptcha.go +++ b/recaptcha.go @@ -29,9 +29,16 @@ import ( // R type represents an object of Recaptcha and has public property Secret, // which is secret obtained from google recaptcha tool admin interface type R struct { - Secret string - lastError []string - UseRemoteIP bool + Secret string + lastError []string + + // UseRemoteIP should be true if you want to send Client IP to + // recaptcha server. + UseRemoteIP bool + + // TrustXForwardedFor should be true if your application runs behind a + // proxy you can trust. This will only take effect if UseRemoteIP is + // true. TrustXForwardedFor bool }