在 ASP.NET 的服务器端验证 Recaptcha 2 (No CAPTCHA reCAPTCHA)
Posted
技术标签:
【中文标题】在 ASP.NET 的服务器端验证 Recaptcha 2 (No CAPTCHA reCAPTCHA)【英文标题】:Validating Recaptcha 2 (No CAPTCHA reCAPTCHA) in ASP.NET's server side 【发布时间】:2015-03-02 02:45:37 【问题描述】:The new Recaptcha 2 看起来很有希望,但我没有找到在 ASP.NET 的服务器端验证它的方法,
This answer中的if(Page.IsValid)
对旧的Recaptcha有效,对新的Recaptcha无效,
如何在服务器端验证新的 reCAPTCHA?
【问题讨论】:
他们没有休息端点来验证 试试这个。您必须根据响应将用户响应发布到 google ans,然后继续。更多在这里。 developers.google.com/recaptcha/docs/verify @saravanan,你是对的,解决方案应该在这里,我会尝试编码。 试试这个Install-Package reCAPTCH.MVC 如果您正在寻找在 ASP.NET 中组合 Google reCAPTCHA v2 和 v3 的最新解决方案,请查看演示 techtolia.com/Recaptcha 【参考方案1】:在阅读了很多资源之后,我最终写了这个类来处理the new ReCaptcha的验证:
如 Here 所述:当最终用户解决了 reCAPTCHA 时,将在 html 中填充一个新字段 (g-recaptcha-response)。
我们需要读取这个值并将其传递给下面的类来验证它:
在 C# 中:
在您页面后面的代码中:
string EncodedResponse = Request.Form["g-Recaptcha-Response"];
bool IsCaptchaValid = (ReCaptchaClass.Validate(EncodedResponse) == "true" ? true : false);
if (IsCaptchaValid)
//Valid Request
班级:
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.ToLower();
[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
班级:
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
【讨论】:
如果用户不想导入Newtonsoft.Json
并创建一个完整定义的 Json 对象,他们可以只使用来自 System.Web.Script.Serialization
的 javascriptSerializer
并反序列化为一个普通的 'ol 对象,如图所示in this stackexchange answer
你的回答真的很有帮助阿拉。这就是我为消除对 Newtonsoft 的依赖所做的:JavaScriptSerializer js = new JavaScriptSerializer(); MyObject 数据 = js.Deserialize这是一个使用 JavaScriptSerializer 的版本。感谢 Ala 提供此代码的基础。
WebConfig 应用设置 - 在我的例子中,我已将密钥添加到 Web.Config 以允许在环境之间进行转换。如果需要,也可以在这里轻松加密。
<add key="Google.ReCaptcha.Secret" value="123456789012345678901234567890" />
ReCaptcha 类 - 一个简单的类,用于将响应参数连同您的密码一起发布到 Google 并进行验证。使用 .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;
验证响应 - 检查控制器中 g-Recaptcha-Response 表单参数的有效性(或网络表单的代码)并采取适当的措施。
var encodedResponse = Request.Form["g-Recaptcha-Response"];
var isCaptchaValid = ReCaptcha.Validate(encodedResponse);
if (!isCaptchaValid)
// E.g. Return to view or set an error message to visible
【讨论】:
对于那些对最简单的实现感兴趣的人来说,这似乎是一个很好的解决方案,尤其是在不使用 Newtonsoft 库的情况下。 我选择了这个解决方案。简单,很好的解释,易于理解。 如果已经是客户端验证,这不起作用,因为响应只成功一次,而不是两次,所以如果已经通过客户端验证,服务器第二次验证将返回 false... 【参考方案3】:这些答案中的大多数似乎都比需要的复杂。他们也没有指定有助于防止拦截攻击的 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 (bool)JObject.Parse(response)["success"];
【讨论】:
优秀的解决方案。简单有效。【参考方案4】:您可以使用“IsValidCaptcha()”方法在服务器端验证您的 google recaptcha。在以下方法中将您的密钥替换为“YourRecaptchaSecretkey”。
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;
同时创建以下类。
public class CaptchaResult
public string success get; set;
【讨论】:
【参考方案5】:根据doc,您只需将您的密钥和用户对 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 中实现 this 页面。
<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>
假设您希望控制器保存,假设如果验证成功,则在会话中保存“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");
【讨论】:
【参考方案6】:这是我的 Ala 解决方案的分支,目的是:
在 POST 中发送参数 清理表单输入 包括请求者 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;
【讨论】:
【参考方案7】:This article 分步说明如何在您的模型上实现 ReCaptcha 验证属性。
首先,创建 Recaptcha 验证属性。
namespace Sample.Validation
public class GoogleReCaptchaValidationAttribute : ValidationAttribute
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
Lazy<ValidationResult> errorResult = new Lazy<ValidationResult>(() => new ValidationResult("Google reCAPTCHA validation failed", new String[] validationContext.MemberName ));
if (value == null || String.IsNullOrWhiteSpace( value.ToString()))
return errorResult.Value;
IConfiguration configuration = (IConfiguration)validationContext.GetService(typeof(IConfiguration));
String reCaptchResponse = value.ToString();
String reCaptchaSecret = configuration.GetValue<String>("GoogleReCaptcha:SecretKey");
HttpClient httpClient = new HttpClient();
var httpResponse = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret=reCaptchaSecret&response=reCaptchResponse").Result;
if (httpResponse.StatusCode != HttpStatusCode.OK)
return errorResult.Value;
String jsonResponse = httpResponse.Content.ReadAsStringAsync().Result;
dynamic jsonData = JObject.Parse(jsonResponse);
if (jsonData.success != true.ToString().ToLower())
return errorResult.Value;
return ValidationResult.Success;
然后在你的模型上添加验证属性。
namespace Sample.Models
public class XModel
// ...
[Required]
[GoogleReCaptchaValidation]
public String GoogleReCaptchaResponse get; set;
最后,您只需调用 ModelState.IsValid 方法
namespace Sample.Api.Controllers
[ApiController]
public class XController : ControllerBase
[HttpPost]
public IActionResult Post(XModel model)
if (!ModelState.IsValid)
return BadRequest(ModelState);
// ...
等等! :)
【讨论】:
完美。此外,在属性类中添加“使用 Microsoft.Extensions.Configuration”。 IntelliSense 对我来说并不明显。【参考方案8】:此处发布另一个示例:
RecaptchaV2.NET (Github)
它还实现了 Recaptcha 2.0 的安全令牌选项(查看该位的完整源代码,我已经删除了相关的代码片段,仅用于验证结果)。
这个不依赖 newtonsoft 的 json 解析器,而是使用内置的 .NET 解析器。
这里是来自 RecaptchaV2.NET 库(来自 recaptcha.cs)的相关 sn-p 代码:
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());
【讨论】:
额外的 HttpWebRequest URL 参数“remoteip”有什么作用?我们没有使用“remoteip”参数,并且在接收请求响应时遇到间歇性问题。问题发生时响应为空。【参考方案9】:Google 的 ReCaptcha API 不再接受负载作为 GET 请求中的查询字符串参数。除非我通过 HTTP POST 发送数据,否则 Google 总是返回“错误”成功响应。这是 Ala 的(非常棒!)类的更新,它将有效负载 POST 到 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;
【讨论】:
【参考方案10】:在服务器端使用动态验证验证码
调用函数
[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;
【讨论】:
【参考方案11】:我在this so post 中发布的示例使用 Newtonsoft.JSON 反序列化完整返回的 JSON,将数据发布到 Google(而不是使用查询字符串)将相关变量存储在 web.config 中,而不是硬编码。
【讨论】:
以上是关于在 ASP.NET 的服务器端验证 Recaptcha 2 (No CAPTCHA reCAPTCHA)的主要内容,如果未能解决你的问题,请参考以下文章
当我在 ASP.Net 中使用 CustomValidator 服务器端验证时,Simplemodal 关闭
如何让 jQuery 验证生成与服务器端 ASP .NET MVC 验证相同的标记?
使用正则表达式的 ASP.NET C# 客户端和服务器端验证
使用 qTip jQuery 插件的 ASP.NET MVC 验证