ASP .NET Google reCAPTCHA s3 Usage

ASP .NET Google reCAPTCHA s3 Usage


I open the source code I have used on this site for you, I feel like you will try to hack. But my self-confidence is full and easy :)

<form asp-action="Login" asp-controller="Login" method="post">
	<input asp-for="Email">
	<input asp-for="Password" type="password">
	<button type="submit">Login</button>
</form>

Let's have a clean form. Let's add security to this. Let's get you right here.

  • Create an account for yourself. reCAPTCHA
  • Here we will click the + button and get a key.
  • Enter the name in the label field.
  • Select reCAPTCHA s3 as the type.
  • Enter your domain name.
  • Add localhost to extra domains for testing.
  • Click Submit.

After this process, you will get reCAPTCHA s3 SITE KEY and SITE HIDDEN KEY and you will be able to access the API. (In our article, we will address them as keys and secrets.)

We are done with the Google page. Let's code it ...

** CLIENT SIDE ** Let's restructure our insecure form above. (Friends who do not use jquery, I think they can reconfigure the function, for those who do not know, comments will be added.)

<!DOCTYPE html>
<html lang="en">
<body>
<form asp-action="Login" asp-controller="Login" method="post" id="pc-form" asp-antiforgery="true">
	<p>@ViewBag.Error</p>
	<input asp-for="Email">
	<input asp-for="Password" type="password">
	<button class="g-recaptcha"
		data-sitekey="GoogleRecaptchaKey"
		data-callback="pcOnSubmit"
    data-action="submit">Login</button>
</form>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
    function pcOnSubmit() {
        let pcForm = $('#pc-form');
        pcForm.submit();
    }
</script>
</body>
</html>

You will see multiple solutions on the internet. Most of them use S3 wrong. The detail part is Google reCAPTCHA gives a token to the user to see if the user is reliable and you check your server to see if that token is reliable. These tokens have a duration of 2 minutes and this has been ignored for some of the resources on the net. In this article, you will not have such a problem because you receive a new token every time you press the button. Also note that we removed the submit type of the button.

** BACKEND ** When the user presses the button, google reCAPTCHA token information will be sent to the server along with the Request data. Let's google the incoming token and find out if this user is reliable.

  1. Our reCAPTCHA Response Model
    public class ReCaptchaTokenResponse
    {
        [JsonProperty("success")] 
        public bool Success { get; set; }

        [JsonProperty("score")] 
        public decimal Score { get; set; }

        [JsonProperty("action")]
        public string Action { get; set; }

        [JsonProperty("error-codes")] 
        public List<string> ErrorCodes { get; set; }
    }
  1. Controller
public class LoginController : BaseController
{
    private readonly IHttpClientFactory _httpClientFactory;

    public LoginController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(WebLoginReq model)
    {
        if (!ModelState.IsValid)
            return View("~/Views/Login/Index.cshtml");
        try
        {
            string token = Request.Form["g-recaptcha-response"];
            using var client = _httpClientFactory.CreateClient();
            var response = await client.GetStringAsync($"https://www.google.com/recaptcha/api/siteverify"
                                                       + $"?secret={GoogleRecaptchaSecret}"
                                                       + $"&response={token}");
            var tokenResponse = JsonConvert.DeserializeObject<ReCaptchaTokenResponse>(response);
            if (!tokenResponse.Success)
                throw new Exception("ARE YOU ROBOT");

            // database login operations. Check if there is any user. Do your login.

            return RedirectToAction("Index", "Home");
        }
        catch (Exception ex)
        {
            ViewBag.Error = ex.Message;
            return View("~/Views/Login/Index.cshtml");
        }
    }
}

Happy Coding!

An error has occurred. This application may no longer respond until reloaded. Reload 🗙