Recaptcha 2 valideren (geen CAPTCHA reCAPTCHA) aan de serverzijde van ASP.NET

De nieuwe Recaptcha 2ziet er veelbelovend uit, maar ik heb geen manier gevonden om het te valideren aan de serverzijde van ASP.NET,

if(Page.IsValid)in Dit antwoord, is geldig voor de oude Recaptcha, maar niet voor de nieuwe,

Hoe de nieuwe reCAPTCHA valideren aan de serverzijde?


Antwoord 1, autoriteit 100%

Na het lezen van veel bronnen, heb ik uiteindelijk deze les geschreven om de validatie van de nieuwe ReCaptcha:

Zoals vermeld Hier: wanneer een reCAPTCHA is opgelost door de eindgebruiker, verschijnt een nieuw veld (g-recaptcha-response) wordt ingevuld in HTML.

We moeten deze waarde lezen en doorgeven aan de onderstaande klasse om deze te valideren:

In C#:

In de code achter uw pagina :

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

De klas:

 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;
    }

In VB.NET:

In de code achter uw pagina :

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

De klas:

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

Antwoord 2, autoriteit 29%

Hier is een versie die de JavaScriptSerializer gebruikt. Bedankt Ala voor de basis voor deze code.

Instelling WebConfig-app
Ik heb in mijn geval de geheime sleutel aan de Web.Config toegevoegd om transformaties tussen omgevingen mogelijk te maken. Het kan hier indien nodig ook eenvoudig worden versleuteld.

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

De ReCaptcha-klasse– Een eenvoudige klasse om de responsparameter samen met uw geheim naar Google te posten en te valideren. Het antwoord wordt gedeserialiseerd met behulp van de .Net JavaScriptSerializer-klasse en van dat waar of onwaar geretourneerd.

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;
    }
}

Bevestig het antwoord– Controleer de geldigheid van de g-Recaptcha-Response-formulierparameter in uw Controller (of code achter voor een webformulier) en onderneem de juiste actie.

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
}   

Antwoord 3, autoriteit 13%

De meeste van deze antwoorden lijken ingewikkelder dan nodig. Ze specificeren ook niet het IP-adres dat een onderscheppingsaanval zal helpen voorkomen (https://security.stackexchange.com/questions/81865/is-there-any-reason-to-include-the-remote-ip-when-using-recaptcha) . Dit is wat ik heb afgesproken

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"];
    }
}

Antwoord 4, autoriteit 4%

U kunt de “IsValidCaptcha()”-methode gebruiken om uw Google-recaptcha aan de serverzijde te valideren. Vervang uw geheime sleutel door “YourRecaptchaSecretkey” op de volgende manier.

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;
 }

Maak ook de volgende klas aan.

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

Antwoord 5, autoriteit 3%

Volgens het docpost je gewoon je geheime sleutel en het antwoord van de gebruiker op de API en lees geretourneerde eigenschap “succes”

KORT ANTWOORD:

       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!!!

VOLLEDIG VOORBEELD:

Stel dat u dezepagina implementeert in 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>

En stel dat je wilt dat de controller wordt opgeslagen, laten we zeggen de “I_AM_NOT_ROBOT”-vlag in de sessie als de verificatie is gelukt:

   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");
    }

Antwoord 6, autoriteit 2%

Hier is mijn afsplitsing van Ala’s oplossing om:

  • verzend parameter in POST
  • om de formulierinvoer te zuiveren
  • vermeld het IP-adres van de aanvrager
  • bewaar het geheim in Web.Config:

In de controller:

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

De nutsklasse:

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;
        }
    }       
}

Antwoord 7

Dit artikel geef duidelijke stapsgewijze uitleg over hoe u een ReCaptcha-validatiekenmerk op uw model implementeert.

Maak eerst het Recaptcha-validatiekenmerk.

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;
        }
    }
}

Voeg vervolgens het validatiekenmerk toe aan uw model.

namespace Sample.Models
{
    public class XModel
    {
        // ...
        [Required]  
        [GoogleReCaptchaValidation]  
        public String GoogleReCaptchaResponse { get; set; }
    }
}

Ten slotte hoeft u alleen maar de methode ModelState.IsValid aan te roepen

namespace Sample.Api.Controllers
{
    [ApiController]
    public class XController : ControllerBase
    {
        [HttpPost]
        public IActionResult Post(XModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            // ...
        }
    }
}

Et voilà! 🙂


Antwoord 8

Een ander voorbeeld wordt hier gepost:

RecaptchaV2.NET (Github)

Het implementeert ook de veilige tokenoptie van Recaptcha 2.0 (kijk naar de volledige broncode voor dat stukje, ik heb ALLEEN relevante stukjes code verwijderd om een ​​resultaat te valideren).

Deze is niet afhankelijk van de json-parser van newtonsoft en gebruikt in plaats daarvan de ingebouwde .NET-parser.

Hier is het relevante codefragment uit de RecaptchaV2.NET-bibliotheek (van 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());
    }
  }
}

9

Dynamisch gebruiken om recaptcha aan serverzijde te valideren

Belfunctie

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

Functieverklaring

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;
}

Antwoord 10

het voorbeeld dat ik heb gepost in dit dus postgebruikt Newtonsoft.JSON om de volledig geretourneerde JSON te deserialiseren, post de gegevens naar Google (in tegenstelling tot het gebruik van een querystring) slaat de relevante variabelen op in de web.config in plaats van hard gecodeerd.

Other episodes