新しいRecaptcha 2 は有望に見えますが、ASP.NETのサーバー側でそれを検証する方法を見つけられませんでした。
if(Page.IsValid)
in この回答 は、古いRecaptchaには有効ですが、新しいRecaptchaには有効ではありません。
サーバー側で新しいreCAPTCHAを検証する方法は?
多くのリソースを読んだ後、 新しいReCaptcha の検証を処理するためにこのクラスを書くことになりました。
前述のとおり、 ここ :エンドユーザーが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
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フォームパラメーター(またはWebフォームのコードビハインド)の有効性を確認し、適切なアクションを実行します。
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
}
これらの答えのほとんどは、必要以上に複雑に思えます。また、傍受攻撃の防止に役立つ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"];
}
}
「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; }
}
参照 リンク
以下は、Alaのソリューションの私のフォークです。
コントローラー内:
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;
}
}
}
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!!!
完全な例:
this page inIamNotARobotLogin.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>
そして、コントローラが保存されることを望んでいるとしましょう、検証が成功した場合、セッションで「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");
}
別の例をここに掲載します。
また、Recaptcha 2.0のセキュアトークンオプションも実装します(そのビットの完全なソースコードを見てください。結果を検証するために関連するコードのみを削除しました)。
これは、newtonsoftのjsonパーサーに依存せず、代わりに組み込みの.NETパーサーを使用します。
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());
}
}
}
GoogleのReCaptcha APIは、GETリクエストのクエリ文字列パラメーターとしてペイロードを受け入れなくなりました。 HTTP POSTを介してデータを送信しない限り、Googleは常に「false」の成功応答を返しました。以下は、GoogleサービスエンドポイントにペイロードをPOSTするAla(excellent!)クラスの更新です。
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;
}
動的を使用してサーバー側で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;
}
this so post で投稿した例では、Newtonsoft.JSONを使用して、返されたJSON全体をデシリアライズし、(クエリ文字列を使用するのではなく)Googleにデータを投稿し、関連する変数をweb.configに保存します。ハードコーディング。
この記事 モデルに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);
}
// ...
}
}
}
ほら! :)