在ASP.NET的服务器端validationRecaptcha 2(没有CAPTCHA reCAPTCHA)

新的Recaptcha 2看起来很有前景,但是我没有find在ASP.NET的服务器端validation它的方法,

if(Page.IsValid)在这个答案中 ,对旧的Recaptcha有效,但不是新的,

如何在服务器端validation新的reCAPTCHA?

在阅读了很多资源之后,我最终编写了这个类来处理新ReCaptcha的validation:

如这里所提到的:当reCAPTCHA被最终用户解决时,新的字段(g-recaptcha-response)将被填充在HTML中。

我们需要读取这个值并传递给下面的类来validation它:

在C#中:

在你的页面后面的代码中:

 string EncodedResponse = Request.Form["g-Recaptcha-Response"]; bool IsCaptchaValid = (ReCaptchaClass.Validate(EncodedResponse) == "true" ? true : false); if (IsCaptchaValid) { //Valid Request } 

class上:

  using Newtonsoft.Json; public class ReCaptchaClass { public static string Validate(string EncodedResponse) { var client = new System.Net.WebClient(); string PrivateKey = "6LcH-v8SerfgAPlLLffghrITSL9xM7XLrz8aeory"; var GoogleReply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", PrivateKey, EncodedResponse)); var captchaResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<ReCaptchaClass>(GoogleReply); return captchaResponse.Success; } [JsonProperty("success")] public string Success { get { return m_Success; } set { m_Success = value; } } private string m_Success; [JsonProperty("error-codes")] public List<string> ErrorCodes { get { return m_ErrorCodes; } set { m_ErrorCodes = value; } } private List<string> m_ErrorCodes; } 

在VB.NET中:

在你的页面后面的代码中:

 Dim EncodedResponse As String = Request.Form("g-Recaptcha-Response") Dim IsCaptchaValid As Boolean = IIf(ReCaptchaClass.Validate(EncodedResponse) = "True", True, False) If IsCaptchaValid Then 'Valid Request End If 

class上:

 Imports Newtonsoft.Json Public Class ReCaptchaClass Public Shared Function Validate(ByVal EncodedResponse As String) As String Dim client = New System.Net.WebClient() Dim PrivateKey As String = "6dsfH-v8SerfgAPlLLffghrITSL9xM7XLrz8aeory" Dim GoogleReply = client.DownloadString(String.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", PrivateKey, EncodedResponse)) Dim captchaResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(Of ReCaptchaClass)(GoogleReply) Return captchaResponse.Success End Function <JsonProperty("success")> _ Public Property Success() As String Get Return m_Success End Get Set(value As String) m_Success = value End Set End Property Private m_Success As String <JsonProperty("error-codes")> _ Public Property ErrorCodes() As List(Of String) Get Return m_ErrorCodes End Get Set(value As List(Of String)) m_ErrorCodes = value End Set End Property Private m_ErrorCodes As List(Of String) End Class 

这是一个使用JavaScriptSerializer的版本。 感谢Ala为此代码的基础。

WebConfig应用程序设置 – 我在我的情况下添加了密钥到Web.Config以允许在环境之间转换。 如果需要,也可以在这里轻松encryption。

 <add key="Google.ReCaptcha.Secret" value="123456789012345678901234567890" /> 

ReCaptcha类 – 一个简单的类,将响应参数和您的秘密一起发布给Google,并对其进行validation。 使用.Net JavaScriptSerializer类进行反序列化,并返回true或false。

 using System.Collections.Generic; using System.Configuration; public class ReCaptcha { public bool Success { get; set; } public List<string> ErrorCodes { get; set; } public static bool Validate(string encodedResponse) { if (string.IsNullOrEmpty(encodedResponse)) return false; var client = new System.Net.WebClient(); var secret = ConfigurationManager.AppSettings["Google.ReCaptcha.Secret"]; if (string.IsNullOrEmpty(secret)) return false; var googleReply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secret, encodedResponse)); var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); var reCaptcha = serializer.Deserialize<ReCaptcha>(googleReply); return reCaptcha.Success; } } 

validation响应 – 检查控制器中g-Recaptcha-Response表单参数的有效性(或Web表单后面的代码)并采取适当的措施。

 var encodedResponse = Request.Form["g-Recaptcha-Response"]; var isCaptchaValid = ReCaptcha.Validate(encodedResponse); if (!isCaptchaValid) { // Eg Return to view or set an error message to visible } 

我大部分的答案似乎比需要更复杂。 他们也没有指定有助于防止拦截攻击的IP( https://security.stackexchange.com/questions/81865/is-there-any-reason-to-include-the-remote-ip-when-using- recaptcha )。 这就是我所定下的

 public bool CheckCaptcha(string captchaResponse, string ipAddress) { using (var client = new WebClient()) { var response = client.DownloadString($"https://www.google.com/recaptcha/api/siteverify?secret={ ConfigurationManager.AppSettings["Google.ReCaptcha.Secret"] }&response={ captchaResponse }&remoteIp={ ipAddress }"); return JsonConvert.DeserializeObject<RecaptchaResponse>(response).Success; } } private class RecaptchaResponse { [JsonProperty("success")] public bool Success { get; set; } } 

您可以使用“IsValidCaptcha()”方法来validation您的谷歌recaptcha在服务器端。 在下面的方法中用“YourRecaptchaSecretkey”replace你的密钥。

 Public bool IsValidCaptcha() { string resp = Request["g-recaptcha-response"]; var req = (HttpWebRequest)WebRequest.Create (https://www.google.com/recaptcha/api/siteverify?secret=+ YourRecaptchaSecretkey + "&response=" + resp); using (WebResponse wResponse = req.GetResponse()) { using (StreamReader readStream = new StreamReader(wResponse.GetResponseStream())) { string jsonResponse = readStream.ReadToEnd(); JavaScriptSerializer js = new JavaScriptSerializer(); // Deserialize Json CaptchaResult data = js.Deserialize<CaptchaResult>(jsonResponse); if (Convert.ToBoolean(data.success)) { return true; } } } return false; } 

也创build下面的类。

 public class CaptchaResult { public string success { get; set; } } 

参考链接

根据文档,您只需发布您的密钥和用户对API的答案,并阅读返回的“成功”属性

简答题:

  var webClient = new WebClient(); string verification = webClient.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secretKey, userResponse)); if (JObject.Parse(verification)["success"].Value<bool>()) { // SUCCESS!!! 

例如:

假设你在IamNotARobotLogin.cshtml中实现了这个页面。

 <head> <script src="https://www.google.com/recaptcha/api.js" async defer></script> </head> <body> <form action="Login" method="POST"> <div class="g-recaptcha" data-sitekey="your_site_key"></div><br/> <input type="submit" value="Log In"> </form> </body> 

假设您希望控制器保存,假设validation成功,会话中会显示“I_AM_NOT_ROBOT”标志:

  public ActionResult IamNotARobotLogin() { return View(); } [HttpPost] public ActionResult Login() { const string secretKey = "6LcH-v8SerfgAPlLLffghrITSL9xM7XLrz8aeory"; string userResponse = Request.Form["g-Recaptcha-Response"]; var webClient = new System.Net.WebClient(); string verification = webClient.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secretKey, userResponse)); var verificationJson = Newtonsoft.Json.Linq.JObject.Parse(verification); if (verificationJson["success"].Value<bool>()) { Session["I_AM_NOT_A_ROBOT"] = "true"; return RedirectToAction("Index", "Demo"); } // try again: return RedirectToAction("IamNotARobotLogin"); } 

另一个例子是张贴在这里:

RecaptchaV2.NET(Github)

它还实现了Recaptcha 2.0的安全令牌选项(查看该位的完整源代码,我已经剥离了相关的代码段来validation结果)。

这个不依赖于newtonsoft的jsonparsing器,而是使用内置的.NETparsing器。

以下是来自RecaptchaV2.NET库(来自recaptcha.cs)的相关代码片段:

 namespace RecaptchaV2.NET { /// <summary> /// Helper Methods for the Google Recaptcha V2 Library /// </summary> public class Recaptcha { public string SiteKey { get; set; } public string SecretKey { get; set; } public Guid SessionId { get; set; } /// <summary> /// Validates a Recaptcha V2 response. /// </summary> /// <param name="recaptchaResponse">g-recaptcha-response form response variable (HttpContext.Current.Request.Form["g-recaptcha-response"])</param> /// <returns>RecaptchaValidationResult</returns> public RecaptchaValidationResult Validate(string recaptchaResponse) { RecaptchaValidationResult result = new RecaptchaValidationResult(); HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://www.google.com/recaptcha/api/siteverify?secret=" + SecretKey + "&response=" + recaptchaResponse + "&remoteip=" + GetClientIp()); //Google recaptcha Response using (WebResponse wResponse = req.GetResponse()) { using (StreamReader readStream = new StreamReader(wResponse.GetResponseStream())) { string jsonResponse = readStream.ReadToEnd(); JavaScriptSerializer js = new JavaScriptSerializer(); result = js.Deserialize<RecaptchaValidationResult>(jsonResponse.Replace("error-codes", "ErrorMessages").Replace("success", "Succeeded"));// Deserialize Json } } return result; } private string GetClientIp() { // Look for a proxy address first String _ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; // If there is no proxy, get the standard remote address if (string.IsNullOrWhiteSpace(_ip) || _ip.ToLower() == "unknown") _ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; return _ip; } } public class RecaptchaValidationResult { public RecaptchaValidationResult() { ErrorMessages = new List<string>(); Succeeded = false; } public List<string> ErrorMessages { get; set; } public bool Succeeded { get; set; } public string GetErrorMessagesString() { return string.Join("<br/>", ErrorMessages.ToArray()); } } } 

使用dynamicvalidation在服务器端的recaptcha

调用函数

 [HttpPost] public ActionResult ClientOrderDetail(FormCollection collection, string EncodedResponse) { Boolean Validation = myFunction.ValidateRecaptcha(EncodedResponse); return View(); } 

函数声明

 public static Boolean ValidateRecaptcha(string EncodedResponse) { string PrivateKey = "YourSiteKey"; var client = new System.Net.WebClient(); var GoogleReply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", PrivateKey, EncodedResponse)); var serializer = new JavaScriptSerializer(); dynamic data = serializer.Deserialize(GoogleReply, typeof(object)); Boolean Status = data["success"]; string challenge_ts = data["challenge_ts"]; string hostname = data["hostname"]; return Status; } 

Google的ReCaptcha API不再接受有效载荷作为GET请求中的查询string参数。 除非我通过HTTP POST发送数据,Google总是返回一个“错误”的成功响应。 以下是对Ala的(优秀!)类的更新,将有效负载PO​​ST到Google服务端点:

 using Newtonsoft.Json; using System.Net; using System.IO; using System.Text; public class RecaptchaHandler { public static string Validate(string EncodedResponse, string RemoteIP) { var client = new WebClient(); string PrivateKey = "PRIVATE KEY"; WebRequest req = WebRequest.Create("https://www.google.com/recaptcha/api/siteverify"); string postData = String.Format("secret={0}&response={1}&remoteip={2}", PrivateKey, EncodedResponse, RemoteIP); byte[] send = Encoding.Default.GetBytes(postData); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; req.ContentLength = send.Length; Stream sout = req.GetRequestStream(); sout.Write(send, 0, send.Length); sout.Flush(); sout.Close(); WebResponse res = req.GetResponse(); StreamReader sr = new StreamReader(res.GetResponseStream()); string returnvalue = sr.ReadToEnd(); var captchaResponse = JsonConvert.DeserializeObject<RecaptchaHandler>(returnvalue); return captchaResponse.Success; } [JsonProperty("success")] public string Success { get { return m_Success; } set { m_Success = value; } } private string m_Success; [JsonProperty("error-codes")] public List<string> ErrorCodes { get { return m_ErrorCodes; } set { m_ErrorCodes = value; } } private List<string> m_ErrorCodes; } 

这是我的解决scheme,以便:

  • 在POST中发送参数
  • 清理表单input
  • 包括请求者的IP地址
  • 存储在Web.Config的秘密:

在控制器中:

 bool isCaptchaValid = await ReCaptchaClass.Validate(this.Request); if (!isCaptchaValid) { ModelState.AddModelError("", "Invalid captcha"); return View(model); } 

实用程序类:

 public class ReCaptchaClass { private static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static string SecretKey = System.Configuration.ConfigurationManager.AppSettings["Google.ReCaptcha.Secret"]; [JsonProperty("success")] public bool Success { get; set; } [JsonProperty("error-codes")] public List<string> ErrorCodes { get; set; } public static async Task<bool> Validate(HttpRequestBase Request) { string encodedResponse = Request.Form["g-Recaptcha-Response"]; string remoteIp = Request.UserHostAddress; using (var client = new HttpClient()) { var values = new Dictionary<string, string> { {"secret", SecretKey}, {"remoteIp", remoteIp}, {"response", encodedResponse} }; var content = new FormUrlEncodedContent(values); var response = await client.PostAsync("https://www.google.com/recaptcha/api/siteverify", content); var responseString = await response.Content.ReadAsStringAsync(); var captchaResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<ReCaptchaClass>(responseString); if ((captchaResponse.ErrorCodes?.Count ?? 0) != 0) { log.Warn("ReCaptcha errors: " + string.Join("\n", captchaResponse.ErrorCodes)); } return captchaResponse.Success; } } } 

我发布在这个post中的例子使用Newtonsoft.JSON来反序列化完整的返回的JSON,将数据发布到Google(而不是使用查询string)将相关variables存储在web.config而不是硬编码。