[ASP.NET MVC] 使用 Google reCAPTCHA 圖像、圖形驗證(我不是機器人)
前言:
常常看到些網站在登入時或者在需要比較安全操作(銀行轉帳)的時候,都會需要填入辨識圖形上所出現的文字或數字,目的是要辨別是 "真人" 在操作,避免有心人士做惡意的攻擊。比較常見的就是使用機器人重複嘗試登入密碼(暴力破解),所以才會有圖形驗證的產生。以下常見的圖形驗證:
滑鼠點擊位置辨識:
純數字:
文字數字線條干擾:
不過現在影像辨識技術已經非常發達了以上這些方法都是蠻容易就可以輕易繞過,
甚至有些連人都辨別不太出來的機器都可以辨別.....
之後 Google reCAPTCHA 就改變成以下的方式,背後原理不太清楚,
不過大致上可以猜測應該是預估你的滑鼠行為或者是停留時間來判斷等等…
利用圖形選擇方式也比較人性化XD
如何使用:
先到 Google reCAPTCHA 註冊基本資訊,取得API KEY:
這邊要注意網域名稱要設定正確,否則當 reCAPTCHA 辨別到你的網址不是你所設定的網域就會出現以下錯誤訊息:
註冊完後會得到以下資訊:
- 私鑰:後端驗證用
- reCAPTCHA 的JavaScript檔案:放到</head>結尾前
- <div….:圖形驗證的程式碼,放到網頁中你想呈現的位置上
介紹兩種方式:
- 使用別人寫好的,NuGet 搜尋 "GoogleRecaptcha"
- 自己寫
使用 GoogleRecaptcha
- 專案右鍵 > Manage NuGet Packages
- 搜尋 GoogleRecaptcha、GoogleRecaptchaMvc(兩個都要裝)
- 安裝
GoogleRecaptchaMvc 是可以在Razor 中使用 RecaptchaV2 方法,參數為註冊時的 SiteKey:
1: @Html.RecaptchaV2("6LdQaxATAAAAAB7UuxNH4lIoC_0wcJE3scx-QJ5v")
記得要引用 reCAPTCHA 的 js 完整如下:
1: @using GoogleRecaptchaMvc
2: <!DOCTYPE html>
3:
4: <html>
5: <head>
6: <title>GoogleRecaptcha</title>
7: <script src='https://www.google.com/recaptcha/api.js'></script>
8: </head>
9: <body>
10: @using (Html.BeginForm("Index", "Home", FormMethod.Post))
11: {
12: <div>
13: @Html.RecaptchaV2("6LdQaxATAAAAAB7UuxNH4lIoC_0wcJE3scx-QJ5v")
14: </div>
15: }
16: </body>
17: </html>
前端部分就已經完成了,夠簡單吧XD
去看 GoogleRecaptchaMvc 的 RecaptchaV2 擴充方法其實就是幫你組合起來:
1: public static IHtmlString RecaptchaV2(this HtmlHelper helper, string siteKey)
2: {
3: var htmlString = String.Format("<div class='g-recaptcha' data-sitekey='{0}'></div>", siteKey);
4: return new HtmlString(htmlString);
5: }
接下來處理後端(以下節錄自官網的 Demo Code):
1: using System.Web.Mvc;
2: using GoogleRecaptcha;
3:
4: namespace Google.reCaptcha.WEB.Controllers
5: {
6: public class HomeController : Controller
7: {
8: // GET: Home
9: public ActionResult Index()
10: {
11: return View();
12: }
13:
14: [HttpPost]
15: public ActionResult Index(FormCollection form)
16: {
17: IRecaptcha<RecaptchaV2Result> recaptcha = new RecaptchaV2(new RecaptchaV2Data(){
18: Secret = "6LdQaxATAAAAACWOZDLB5C06RfW_0qhXJYagQ9iF"
19: });
20:
21: // Verify the captcha
22: var result = recaptcha.Verify();
23: if (result.Success) // Success!!!
24: {
25: //TODO: write code here
26: }
27: return View();
28: }
29: }
30: }
Secret 帶入當初註冊的私鑰,接下來就是用 Verify() 方法看回傳是不是 true 或 false 來判斷。
這邊可能會發現,诶? 他沒有從 from 物件抓取前端傳回來的 token 怎麼驗證?
其實他在 new RecaptchaV2Data() 的時候就抓取了前端的 Form["g-recaptcha-response"]欄位,
所以在使用上就變得更簡單了。
自己寫
前端部分:
- 先引用reCAPTCHA的JS (6行)
- 放入要呈現的位置(10行)
1: <!DOCTYPE html>
2:
3: <html>
4: <head>
5: <title>title</title>
6: <script src='https://www.google.com/recaptcha/api.js'></script>
7: </head>
8: <body>
9: <div>
10: <div class="g-recaptcha" data-sitekey="6LdQaxATAAAAAB7UuxNH4lIoC_0wcJE3scx-QJ5v"></div>
11: </div>
12: </body>
13: </html>
前端完成:
後端部分:
可以先看 官方文件API 文件 :
- POST 方式
- URL 是 https://www.google.com/recaptcha/api/siteverify
- secret 必要參數:私鑰
- response 必要參數:前端傳回來的 token
- remoteip 選填:使用者IP
接下來我們實作一個類別 GoogleReCaptcha:
- 組合POST Parameter
- 發送Request
- 取回結果
1: public class GoogleReCaptcha
2: {
3: public bool Success { get; set; }
4: public bool GetCaptchaResponse(string message)
5: {
6: try
7: {
8: using (var client = new HttpClient())
9: {
10: var content = new FormUrlEncodedContent(new[]{
11: new KeyValuePair<string, string>("secret", "{YourSecretKey}"),
12: new KeyValuePair<string, string>("response", message),
13: });
14:
15: var result = client.PostAsync("https://www.google.com/recaptcha/api/siteverify", content).Result;
16: var resultContent = result.Content.ReadAsStringAsync().Result;
17: var data = JsonConvert.DeserializeObject<GoogleReCaptcha>(resultContent);
18: return data.Success;
19: }
20: }
21: catch{return false;}
22: }
23: }
使用 GoogleReCaptcha :
- 帶入前端傳來的token
- 會回傳 ture 或 false
另外其實在 Google API 文件中還有提到回傳錯誤的 error code 的說明,這部分就沒有針對此實作了。
專案範例以上傳 GitHub 有興趣的可以自行嘗試看看。
如有錯誤還請各位先進前輩們不吝嗇的指教,謝謝。