1. Giới thiệu

Capcha là công cụ quen thuộc với nhiều người giúp cho website không bị spam bởi các công cụ tự động (tool hay script, ...).  Ví dụ website bạn có chức năng cho phép người dùng góp ý về những dịch vụ của website tuy nhiên nếu chúng ta không có cơ chế chặn những request spam từ những công cụ tự động, thì hậu quả là website sẽ tràn ngập những comment vô nghĩa - làm xấu đi hình ảnh của website cũng như là dung lượng lưu trữ bị tiêu tốn vô ích chưa kể tình huống xấu nhất website bị hết băng thông hay hết dung lượng database và dẫn đến ngưng hoạt động.

Trong những tình huống nói trên, CapCha đươc đề xuất là giải pháp hàng đầu bởi sự hiệu quả, đơn giản, dễ dàng implement. Chức năng chính của Capcha chính là phân biệt request đó từ người dùng thật hay từ các tools tự động bằng các dòng chữ khó hiểu đối với các tools này nhưng lại có thể đọc được bởi con người.

Nhiều người chúng ta chắc hẳn cũng từng tiếp xúc ít nhiều với các công cụ Capcha, nhưng nhiều nhất vẫn là công cụ reCapcha của Google, như các hình ảnh dưới đây:

2. Đăng ký Google reCapcha

Google cung cấp miễn phí công cụ reCapcha cho các website, tuy nhiên điều này đồng nghĩa rằng chúng ta đồng ý cho Google thu thâp dữ liệu từ website và người dùng của chúng ta. Các bạn nên cân nhắc và đọc kỹ điều khoản sử dụng trước khi đăng ký Google reCapcha và sử dụng trên trang web của bạn.

Để đăng ký Google reCapcha đầu tiên chúng ta vào link: 

https://www.google.com/recaptcha/admin

Giao diện tương tự như hình bên dưới:

Để đăng ký cho website mới, các bạn click vào dấu + ở bên phải màn hình giao diện:

Trong phần Label các bạn nhập ghi chú ý nghĩa của reCapcha này, ví dụ như "Đăng ký reCapcha cho The Code Root" chẳng hạn.

Các bạn có thể tùy chọn phiên bản reCapcha áp dụng cho website, version 3 và version 2, riêng version 1 đã outdate và Google không còn hỗ trợ nữa.

Và tiếp theo các bạn cần nhập domain của website vào, ví dụ như: thecoderoot.com. Các bạn lưu ý rằng sau khi nhập hết thông tin Google sẽ kiểm tra quyền sở hữu website bằng cách gửi mail xác nhận đến địa chỉ email của bạn, và key đăng ký cho một website là duy nhất, nghĩa là bạn chỉ có thể sử dụng 1 key đăng ký cho 1 website tương ứng.

Và tất nhiên để có thể sử dụng được dịch vụ reCapcha bạn phải đồng ý với những điều khoản được đưa ra bởi Google:

 

Hoàn tất đăng ký bạn sẽ nhận được 1 cặp key để sử dụng cho Google reCapcha, bao gồm siteKey và secretKey

Để sử dụng reCAPTCHA bạn cần khai báo các đường dẫn Js cần thiết. reCAPTCHA hỗ trợ 40 ngôn ngữ người dùng, trong trường hợp mặc định reCAPTCHAsẽ hiển thị ngôn ngữ theo vị trí địa lý của người dùng (Dựa trên địa chỉ IP).

<!-- English language -->
<script src='https://www.google.com/recaptcha/api.js?hl=en'></script>
 
<!-- Vietnamese language -->
<script src='https://www.google.com/recaptcha/api.js?hl=vi'></script>
 
<!-- Auto detecting language -->
<script src='https://www.google.com/recaptcha/api.js'></script>

3. Tích hợp vào ứng dụng.

  • siteKey: được đặt ở tag HTML mà bạn muốn người dùng sẽ nhập capCha ở đấy, ví dụ như form Login, hoặc khung comment ý kiến chẳng hạn:
    <script src="https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key"></script>
      <script>
      grecaptcha.ready(function() {
          grecaptcha.execute('reCAPTCHA_site_key', {action: 'homepage'}).then(function(token) {
             ...
          });
      });
      </script>
    
    <form action="/login" method="post">
     <!-- reCAPTCHA -->
          <div class="g-recaptcha"
              data-sitekey="xxxxxxxxxxxxxxxxxxxx-xhfgB">
    </div>
     <input name="username" />
     <input name="password"
    </form>

    Giá trị trường data-sitekey ở trên chính là siteKey đã được đăng ký. Khi người dùng check vào "I'm not a robot", một Ajax request sẽ tự động gửi tới dịch vụ Google reCAPTCHA và nhận được một mã số xác thực nó được lưu trữ trên một Hidden field (g-recaptcha-response) của form. 

  • secretKeys: là Key mà ứng dụng web của chúng ta dùng để tương tác với server Google. 

Quy trình kiểm tra reCapcha: 

  1. User nhập form kèm với capCha bằng field ẩn "g-recaptcha-response" gởi đến Backend Java .
  2. Backend Java nhận dữ liệu form và dữ liệu capCha bằng query param "g-recaptcha-response". 
  3. Backend Java gửi dữ liệu reCapcha của người dùng và kèm theo secrectKey đến Google Server để kiểm tra người dùng có hợp lệ hay không.
  4. Server Backend dựa trên kết quả từ Google và quyết định cho phép người dùng được truy cập tiếp tục hay phải nhập lại capCha.

Trong version 3, Google Capcha sẽ trả thêm 1 trường nữa cho kết quả verify là trường score (điểm) dựa trên mức độ chính xác mà người dùng (hoặc bot) trả lời câu hỏi. Cao nhất là 1.0 (là con người tương tác) và thấp nhất là 0 (chắc chắn là bot). Và chúng ta có thể linh hoạt hơn trong việc ứng dụng trường này, ví dụ chúng ta chỉ chấp nhận những câu trả lời từ 0.5 trở lên cho chức năng comment, và chỉ cần 0.25 điểm trở lên cho form đăng ký. Nói chung là logic chức năng của web sẽ trở nên linh hoạt hơn.

Các usecase nên ứng dụng Capcha theo khuyến cáo của Google:

  • homepage: Nên áp dụng capCha cho những traffic cùng 1 địa chỉ IP liên tục trong 1 thời gian quá ngắn, nghi ngờ khả năng cao đến từ những con Bot tự động mà đối phương muốn spam web của bạn.
  • login: tránh bị login theo kiểu bruce-force, hạn chế tài khoản người dùng bị tấn công.
  • social: những chức năng comment, lời mời kết bạn hay lời mời chào những dịch vụ bên ngoài nên có capCha để hạn chế spam.
  • e-commerce: với những ứng dụng bán hàng điều này rất cần thiết để tránh những cuộc tấn công spam vào chức năng mua hàng, tương tác giao dịch với hệ thống, những request spam này không những làm Hệ Thống phải xử lý những giao dịch vô giá trị mà còn khiến business của Hệ Thống bị ảnh hưng.

Tiếp theo là phần hướng dẫn tích hợp kiểm tra capCha của người dùng trên Server, trong ví dụ này người viết sử dụng Framework Spring Boot để làm ví dụ.

Tích hợp vào Spring Boot:

Đầu tiên chúng ta cần một project Spring Boot cơ bản. Các bạn có thể lấy source code từ bài hướng dẫn Hello World tại đây.

Thư viện Maven:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0
	https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-boot-google-re-capcha</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- enable live reload -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20180813</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- Package as an executable jar/war -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

 

GoogleCapchaService class:

package thecoderoot.tutorial.capcha.service;

import org.json.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

@Service
public class GoogleCapchaService {
    private static final String SECRETS_KEY = "xxxxxxxxxxxxxxxxxxx-fswd";

    private static final String GOOGLE_ENDPOINT_URL = "https://www.google.com/recaptcha/api/siteverify";

    public boolean verifyGoogleCapcha(String capChaResponse){
        RestTemplate restTemplate = new RestTemplate();
        String params = "secret=" + SECRETS_KEY + "&response=" + capChaResponse;
        String requestUrl = GOOGLE_ENDPOINT_URL + "?" + params;

        String response = restTemplate.getForObject(requestUrl, String.class);
        //==> {"success": true} or {"success": false}

        if (!StringUtils.isEmpty(response)){
            org.json.JSONObject jsonObject = new JSONObject(response);
            return jsonObject.getBoolean("success");
        }

        return false;
    }
}

 

AuthenticationController:

package thecoderoot.tutorial.capcha.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import thecoderoot.tutorial.capcha.service.GoogleCapchaService;
import thecoderoot.tutorial.capcha.service.UserService;

@RestController
public class AuthenticationController {

    @Autowired
    private GoogleCapchaService capchaService;

    @Autowired
    private UserService userService;

    @GetMapping(value = "/login")
    public String showLoginPage(){
        return "login";
    }

    @PostMapping(value = "/login")
    public String handleLogin(@RequestParam(value = "g-recaptcha-response")String capChaResponse,
                              @RequestParam(value = "username") String username,
                              @RequestParam(value = "password") String password,
                              Model model){
        //capcha does not match
        if (!capchaService.verifyGoogleCapcha(capChaResponse)){
            model.addAttribute("YOu have failed in Google Capcha");
            return "login";
        }

        //wrong username or password
        if (!userService.checkUserLogin(username, password)){
            model.addAttribute("Username and password does not match");
            return "login";
        }

        //login successfully
        return "success";
    }
}

 

UserService:

package thecoderoot.tutorial.capcha.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public boolean checkUserLogin(String username, String password){
        //do some check
        return true;
    }
}

 

login.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login With Google Capcha</title>

    <!-- Auto detecting language -->
    <script src='https://www.google.com/recaptcha/api.js'></script>
    <script src="https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key"></script>
    <script>
  grecaptcha.ready(function() {
      grecaptcha.execute('reCAPTCHA_site_key', {action: 'homepage'}).then(function(token) {
         ...
      });
  });
  </script>
</head>
<body>

<form action="/login" method="post">
    <input name="username" />
    <input name="password" />
    <div class="g-recaptcha" data-sitekey="xxxxxxxxxxxxxxxxxxxx-xhfgB"></div>
</form>
</body>
</html>

 

success.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login success with Google reCapcha</title>
</head>
<body>
    User logged in with Google reCapcha successfully
</body>
</html>

Chúc các bạn thành công.

AutoCode.VN

 

minhnhatict@gmail.com Tools