Untuk menerapkan aturan anti-crawler pada aplikasi Android Anda, integrasikan terlebih dahulu kit pengembangan perangkat lunak (SDK) Perlindungan aplikasi. Topik ini memandu Anda melalui langkah-langkah yang diperlukan.
Latar Belakang
SDK Perlindungan aplikasi menandatangani setiap permintaan yang dikirim oleh aplikasi Anda. WAF memverifikasi tanda tangan tersebut untuk membedakan lalu lintas sah dari bot dan aktor jahat lainnya, sehingga melindungi layanan backend aplikasi Anda.
Batasan
Arsitektur ABI Android yang didukung: arm64-v8a dan armeabi-v7a
Tingkat API Android minimum: 16
Setelah memanggil
init, tunggu minimal 2 detik sebelum memanggilvmpSign. SDK memerlukan waktu ini untuk menginisialisasi sepenuhnya kemampuan keamanannya. Penundaan ini bersifat rekomendasi dan dapat disesuaikan sesuai kebutuhan. Penundaan yang lebih singkat dapat mengurangi efektivitas perlindungan.
Prasyarat
Sebelum memulai, pastikan Anda telah memiliki:
Paket SDK untuk aplikasi Android (
tigertally-X.Y.Z-xxxxxx-android.tgz), yang mencakupAliTigerTally_X.Y.Z.aardanAliCaptcha_X.Y.Z.aar. Untuk mendapatkan SDK, ajukan ticket.Kunci otentikasi SDK (appkey). Setelah Anda mengaktifkan Bot Management, buka Bot Management > App Protection dan klik Obtain and Copy AppKey.

Setiap Akun Alibaba Cloud memiliki satu appkey unik yang berlaku untuk semua domain yang dilindungi WAF dan berfungsi lintas integrasi aplikasi Android, iOS, dan HarmonyOS. Contoh format appkey: **OpKLvM6zliu6KopyHIhmneb_u4ekci2W8i6F9vrgpEezqAzEzj2ANrVUhvAXMwYzgY_vc51aEQlRovkRoUhRlVsf4IzO9dZp6nN_Wz8pk2TDLuMo4pVIQvGaxH3vrsnSQiK**Langkah 1: Buat proyek
Buka Android Studio dan buat proyek Android menggunakan wizard konfigurasi. Struktur direktori proyek akan tampak seperti berikut:

Langkah 2: Integrasikan paket AAR
Ekstrak
tigertally-X.Y.Z-xxxxxx-android.tgzdan salin semua file AAR dari folder hasil ekstraksi ke direktorilibsmodul utama Anda. Jalur pastinya mungkin berbeda tergantung konfigurasi proyek Anda.
Buka
build.gradleuntuk modul aplikasi Anda. Tambahkan direktorilibssebagai sumber dependensi lokal dan deklarasikan dependensi kompilasi untuk kedua file AAR serta pustaka pihak ketiga yang diperlukan:PentingGanti
X.Y.Zdalam nama file AAR dengan nomor versi aktual dari paket SDK.dependencies { // ... implementation files('libs/AliTigerTally_X.Y.Z.aar') implementation files('libs/AliCaptcha_X.Y.Z.aar') // Pustaka pihak ketiga yang diperlukan implementation 'com.alibaba:fastjson:1.2.83_noneautotype' implementation 'com.squareup.okhttp3:okhttp:3.11.0' implementation 'com.squareup.okio:okio:1.14.0' }Jika Anda menggunakan ProGuard untuk obfuscasi kode, tambahkan aturan
-keepberikut ke file konfigurasi ProGuard Anda untuk mempertahankan metode API SDK:-keep class com.aliyun.TigerTally.** {*;} -keep class com.aliyun.captcha.* {*;} -keepclassmembers,allowobfuscation class * { @com.alibaba.fastjson.annotation.JSONField <fields>; } -keep class com.alibaba.fastjson.** {*;}
Langkah 3: Filter arsitektur CPU SO
Jika proyek Anda belum menyertakan file SO, tambahkan filter ABI berikut ke file build.gradle Anda:
android {
defaultConfig {
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
}
}
}Langkah 4: Deklarasikan izin aplikasi
Tambahkan izin berikut ke AndroidManifest.xml Anda.
Wajib:
<uses-permission android:name="android.permission.INTERNET"/>Opsional — berikan izin ini untuk meningkatkan akurasi pengumpulan sinyal perangkat:
| Izin | Jenis pemberian | Deskripsi |
|---|---|---|
android.permission.BLUETOOTH | Waktu instalasi | Mengumpulkan status Bluetooth untuk sidik jari perangkat. |
android.permission.READ_PHONE_STATE | Waktu instalasi | Membaca pengenal perangkat seperti IMEI. |
android.permission.ACCESS_WIFI_STATE | Waktu instalasi | Membaca detail koneksi Wi-Fi (SSID, BSSID). |
android.permission.ACCESS_NETWORK_STATE | Waktu instalasi | Membaca status konektivitas jaringan. |
android.permission.READ_EXTERNAL_STORAGE | Runtime (Android 6.0+) | Membaca penyimpanan perangkat untuk pengumpulan sinyal. |
android.permission.WRITE_EXTERNAL_STORAGE | Runtime (Android 6.0+) | Menulis ke penyimpanan perangkat untuk pengumpulan sinyal. |
Izin waktu instalasi diberikan secara otomatis saat instalasi. Izin runtime pada Android 6.0 dan versi lebih baru harus diminta secara dinamis saat runtime; tidak diberikan otomatis saat instalasi.
Langkah 5: Tambahkan kode integrasi
Tambahkan import
import com.alibaba.fastjson.*;
import com.aliyun.tigertally.*;Atur penandatanganan data
Lakukan langkah-langkah berikut secara berurutan: atur pengenal akun pengguna, inisialisasi SDK, lalu tandatangani permintaan.
1. Atur akun pengguna
Tetapkan pengenal pengguna akhir kustom agar Anda dapat menerapkan kebijakan WAF yang ditargetkan per pengguna.
public static int setAccount(String account)| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
account | String | Tidak | String yang mengidentifikasi pengguna. Gunakan format yang telah didesensitisasi. |
Nilai kembali: 0 jika berhasil, -1 jika gagal.
Kode contoh:
// Untuk pengguna tamu, lewati setAccount dan langsung inisialisasi.
// Setelah pengguna masuk, panggil setAccount dan inisialisasi ulang.
String account = "user001";
TigerTallyAPI.setAccount(account);2. Inisialisasi SDK
Panggil init sekali untuk mengumpulkan informasi perangkat. Anda dapat memanggilnya lagi nanti untuk memulai siklus pengumpulan baru untuk konteks bisnis yang berbeda.
public static int init(Context context, String appkey, int collectType,
Map<String, String> otherOptions, TTInitListener listener);Parameter:
| Parameter | Tipe | Wajib | Bawaan | Deskripsi |
|---|---|---|---|---|
context | Context | Ya | — | Konteks aplikasi Anda. |
appkey | String | Ya | — | Kunci otentikasi SDK. |
collectType | int | Ya | — | Mode pengumpulan data. Lihat tabel di bawah. |
otherOptions | Map\<String, String\> | Tidak | null | Opsi tambahan. |
listener | TTInitListener | Tidak | null | Callback untuk hasil inisialisasi. |
Nilai `collectType`:
| Nilai | Deskripsi |
|---|---|
TT_DEFAULT | Mengumpulkan semua data. |
TT_NO_BASIC_DATA | Mengecualikan data perangkat dasar: Nama perangkat, versi Android, dan resolusi layar. |
TT_NO_IDENTIFY_DATA | Mengecualikan pengenal perangkat: IMEI, IMSI, SimSerial, BuildSerial (SN), dan alamat MAC. |
TT_NO_UNIQUE_DATA | Mengecualikan pengenal unik: Open Anonymous Device Identifier (OAID), Google Advertising ID, dan ID Android. |
TT_NO_EXTRA_DATA | Mengecualikan data perangkat tambahan: daftar aplikasi berbahaya/abu-abu, IP LAN, IP DNS, detail Wi-Fi (SSID, BSSID), daftar Wi-Fi terdekat, lokasi, dan data sensor. |
TT_NOT_GRANTED | Mengecualikan semua data privasi di atas. |
Gabungkan beberapa flag pengecualian dengan |. Misalnya, TT_NO_BASIC_DATA | TT_NO_UNIQUE_DATA mengecualikan kedua kategori tersebut. Pilih mode yang memenuhi persyaratan kepatuhan Anda sekaligus mempertahankan cukup data untuk pendeteksian bot yang efektif.
Nilai `otherOptions`:
| Kunci | Deskripsi | Bawaan | Wajib |
|---|---|---|---|
IPv6 | 0: Gunakan IPv4. 1: Gunakan IPv6. | 0 | Tidak |
Intl | 0: Laporkan ke Tiongkok daratan. 1: Laporkan luar Tiongkok daratan. Atur ke 1 untuk instans WAF di luar Tiongkok daratan; jika tidak, gunakan nilai bawaan 0. | 0 | Tidak |
CustomUrl | Nama domain server pelaporan data. Contoh: https://cloudauth-device.us-west-1.aliyuncs.com | — | Tidak |
CustomHost | Host server pelaporan data. Contoh: cloudauth-device.us-west-1.aliyuncs.com | — | Tidak |
Untuk sebagian besar wilayah internasional, mengaturIntlsudah cukup. GunakanCustomUrldanCustomHosthanya saat melaporkan ke titik akhir tertentu, seperti situs US (West).
Callback inisialisasi:
public interface TTInitListener {
// code: kode status pemanggilan inisialisasi
void onInitFinish(int code);
}Kode status callback (`TTCode`):
| Kode | Nilai | Deskripsi |
|---|---|---|
TT_SUCCESS | 0 | SDK berhasil diinisialisasi. |
TT_NOT_INIT | -1 | SDK belum diinisialisasi. |
TT_NOT_PERMISSION | -2 | Izin Android yang diperlukan belum diberikan sepenuhnya. |
TT_UNKNOWN_ERROR | -3 | Kesalahan sistem tidak dikenal. |
TT_NETWORK_ERROR | -4 | Kesalahan jaringan. |
TT_NETWORK_ERROR_EMPTY | -5 | Kesalahan jaringan — badan respons kosong. |
TT_NETWORK_ERROR_INVALID | -6 | Kesalahan jaringan — format respons tidak valid. |
TT_PARSE_SRV_CFG_ERROR | -7 | Gagal mengurai konfigurasi server. |
TT_NETWORK_RET_CODE_ERROR | -8 | Gateway tidak mengembalikan nilai. |
TT_APPKEY_EMPTY | -9 | Appkey kosong. |
TT_PARAMS_ERROR | -10 | Kesalahan parameter. |
TT_FGKEY_ERROR | -11 | Kesalahan perhitungan kunci. |
TT_APPKEY_ERROR | -12 | Versi SDK tidak cocok dengan versi appkey. |
Nilai kembali: 0 jika berhasil, -1 jika gagal.
Kode contoh:
// Ganti dengan appkey Anda yang sebenarnya.
final String appkey = "******";
Map<String, String> options = new HashMap<>();
options.put("IPv6", "0"); // Gunakan IPv4
options.put("Intl", "1"); // Laporkan luar Tiongkok daratan
// Untuk melaporkan secara spesifik ke situs US (West):
// options.put("CustomUrl", "https://cloudauth-device.us-west-1.aliyuncs.com");
// options.put("CustomHost", "cloudauth-device.us-west-1.aliyuncs.com");
// Pengumpulan data lengkap
int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, TigerTallyAPI.TT_DEFAULT, options, null);
// Pengecualian privasi selektif — gabungkan flag dengan |
int privacyFlag = TigerTallyAPI.TT_NO_BASIC_DATA | TigerTallyAPI.TT_NO_UNIQUE_DATA;
int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, privacyFlag, options, null);
// Mengecualikan semua data privasi
int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, TigerTallyAPI.TT_NOT_GRANTED, options, null);
Log.d("AliSDK", "ret:" + ret);3. Hash data (penandatanganan kustom saja)
Lewati langkah ini jika Anda menggunakan penandatanganan bawaan.
Untuk penandatanganan kustom, panggil vmpHash untuk menghitung hash dari data permintaan. Berikan badan permintaan untuk permintaan POST, PUT, dan PATCH, atau URL lengkap untuk permintaan GET dan DELETE. Kemudian tambahkan string whash yang dikembalikan ke header permintaan HTTP ali_sign_whash.
public enum RequestType { GET, POST, PUT, PATCH, DELETE }
public static String vmpHash(RequestType type, byte[] input);| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
type | RequestType | Ya | Metode permintaan HTTP. |
input | byte[] | Ya | Data yang akan di-hash. Tidak boleh berupa string kosong. Untuk GET/DELETE, gunakan URL lengkap (termasuk path dan parameter kueri). |
Nilai kembali: String whash.
Kode contoh:
// Permintaan GET
String url = "https://tigertally.aliyun.com/apptest";
String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.GET, url.getBytes());
Log.d("AliSDK", "whash:" + whash);
// Permintaan POST
String body = "hello world";
String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, body.getBytes());
Log.d("AliSDK", "whash:" + whash);4. Tandatangani data
Panggil vmpSign untuk menghasilkan string wtoken guna otentikasi permintaan. Tambahkan wtoken ke header permintaan HTTP wToken.
Penandatanganan bawaan: berikan badan permintaan sebagai
input.Penandatanganan kustom: berikan whash dari
vmpHashsebagaiinput.
public static String vmpSign(int type, byte[] input);| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
type | int | Ya | Jenis tanda tangan. Harus 1. |
input | byte[] | Ya | Data yang akan ditandatangani. Untuk penandatanganan bawaan: badan permintaan. Untuk penandatanganan kustom: string whash. Jika badan permintaan kosong, berikan null atau "".getBytes("UTF-8"). |
Nilai kembali: String wtoken.
Kode contoh:
// Penandatanganan bawaan
String body = "i am the request body, encrypted or not!";
String wtoken = TigerTallyAPI.vmpSign(1, body.getBytes("UTF-8"));
Log.d("AliSDK", "wToken:" + wtoken);
// Penandatanganan kustom — permintaan GET
String url = "https://tigertally.aliyun.com/apptest";
String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.GET, url.getBytes());
String wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
Log.d("AliSDK", "whash:" + whash + ", wtoken:" + wtoken);
// Penandatanganan kustom — permintaan POST
String body = "hello world";
String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, body.getBytes());
String wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
Log.d("AliSDK", "whash:" + whash + ", wtoken:" + wtoken);Untuk penandatanganan kustom, saat Anda mengonfigurasi kebijakan anti-bot spesifik skenario di Konsol, atur Custom Signature Field ke
ali_sign_whash.Saat menghitung whash untuk permintaan GET, URL input harus persis sama dengan URL akhir yang digunakan dalam permintaan jaringan. Beberapa framework secara otomatis melakukan encode URL terhadap karakter Tionghoa atau parameter — pertimbangkan hal ini saat memberikan URL.
vmpHashtidak menerima string kosong. URL input harus mencakup path atau parameter kueri.Jika
vmpHashatauvmpSignmengembalikan salah satu string berikut, terjadi kesalahan inisialisasi:"you must call init first"—initbelum dipanggil sebelum penandatanganan."you must input correct data"— data input tidak valid."you must input correct type"— jenis input tidak valid.
Lakukan otentikasi dua faktor
Jika WAF menentukan bahwa permintaan mencurigakan, WAF dapat memicu tantangan CAPTCHA untuk memverifikasi pengguna. Gunakan metode berikut untuk menangani alur ini.
1. Periksa apakah tantangan diperlukan
Setelah menerima respons dari server Anda, periksa bidang cookie dan body untuk menentukan apakah WAF telah menandai permintaan tersebut. Gabungkan semua entri Set-Cookie dari header respons menjadi satu string cookie sebelum memanggil metode ini.
public static int cptCheck(String cookie, String body)| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
cookie | String | Ya | Semua cookie dari header respons, digabung menjadi satu string. |
body | String | Ya | Badan respons lengkap. |
Nilai kembali: 0 — permintaan lolos; 1 — tantangan CAPTCHA diperlukan.
Kode contoh:
String cookie = "key1=value1;key2=value2;";
String body = "....";
int recheck = TigerTallyAPI.cptCheck(cookie, body);
Log.d("AliSDK", "recheck:" + recheck);2. Tampilkan slider CAPTCHA
Jika cptCheck mengembalikan 1, buat dan tampilkan slider CAPTCHA kepada pengguna.
public static TTCaptcha cptCreate(Activity activity, TTOption option, TTListener listener);| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
activity | Activity | Ya | Aktivitas saat ini. |
option | TTOption | Ya | Konfigurasi slider. |
listener | TTListener | Ya | Callback untuk hasil verifikasi. |
Nilai kembali: Objek TTCaptcha dengan metode show(), dismiss(), dan getTraceId().
Bidang `TTOption`:
| Bidang | Tipe | Bawaan | Deskripsi |
|---|---|---|---|
cancelable | boolean | — | Apakah mengetuk di luar slider akan menutupnya. |
customUri | String | — | Halaman CAPTCHA kustom (file HTML lokal atau URL remote). |
language | String | — | Bahasa untuk UI slider (misalnya, "cn"). |
Callback `TTListener`:
public interface TTListener {
void success(TTCaptcha captcha, String data); // data = certifyId (token)
void failed(TTCaptcha captcha, String code); // code = kode kesalahan
}Kode kesalahan slider:
| Kode | Deskripsi |
|---|---|
1001 | Verifikasi gagal. |
1002 | Pengecualian sistem. |
1003 | Kesalahan parameter. |
1005 | Verifikasi dibatalkan oleh pengguna. |
8001 | Kesalahan pemanggilan slider. |
8002 | Data verifikasi slider tidak normal. |
8003 | Pengecualian internal verifikasi slider. |
8004 | Kesalahan jaringan. |
Callback failed dipicu saat terdeteksi pengecualian setelah pengguna menyelesaikan gerakan geser, bukan saat pengguna meninggalkan tantangan.Kode contoh:
TTCaptcha.TTOption option = new TTCaptcha.TTOption();
// option.customUri = "file:///android_asset/ali-tt-captcha-demo.html";
option.language = "cn";
option.cancelable = false;
TTCaptcha captcha = TigerTallyAPI.cptCreate(this, option, new TTCaptcha.TTListener() {
@Override
public void success(TTCaptcha captcha, String data) {
Log.d(TAG, "captcha check success:" + data);
}
@Override
public void failed(TTCaptcha captcha, String code) {
Log.d(TAG, "captcha check failed:" + code);
}
});
captcha.show();Contoh praktik terbaik
Contoh end-to-end berikut menunjukkan alur integrasi lengkap: inisialisasi, penandatanganan permintaan, pengiriman permintaan, dan penanganan tantangan CAPTCHA.
package com.aliyun.tigertally.apk;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.aliyun.TigerTally.TigerTallyAPI;
import com.aliyun.TigerTally.captcha.api.TTCaptcha;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class DemoActivity extends AppCompatActivity {
private final static String TAG = "TigerTally-Demo";
private final static String APP_HOST = "******";
private final static String APP_URL = "******";
private final static String APP_KEY = "******";
private final static OkHttpClient okHttpClient = new OkHttpClient();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
doTest();
}
private void doTest() {
Log.d(TAG, "captcha flow");
new Thread(() -> {
// Langkah 1: Inisialisasi SDK.
Map<String, String> options = new HashMap<>();
// options.put("Intl", "1"); // Hapus komentar untuk pelaporan internasional.
int ret = TigerTallyAPI.init(this, APP_KEY, TigerTallyAPI.TT_DEFAULT, options, null);
// int ret = TigerTallyAPI.init(this, APP_KEY, TigerTallyAPI.TT_NOT_GRANTED, null, null); // Tanpa data privasi
Log.d(TAG, "tiger tally init: " + ret);
// Langkah 2: Tunggu minimal 2 detik sebelum menandatangani — inisialisasi bersifat asinkron.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Langkah 3: Tandatangani data permintaan.
String data = "hello world";
String whash = null, wtoken = null;
// Penandatanganan kustom
whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, data.getBytes());
wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
Log.d(TAG, "tiger tally vmp: " + whash + ", " + wtoken);
// Penandatanganan bawaan (tidak perlu vmpHash)
// wtoken = TigerTallyAPI.vmpSign(1, data.getBytes());
// Log.d(TAG, "tiger tally vmp: " + wtoken);
// Langkah 4: Kirim permintaan dan periksa apakah CAPTCHA diperlukan.
doPost(APP_URL, APP_HOST, whash, wtoken, data, (code, cookie, body) -> {
int recheck = TigerTallyAPI.cptCheck(cookie, body);
Log.d(TAG, "captcha check result: " + recheck);
if (recheck == 0) return;
this.runOnUiThread(this::doShow);
});
}).start();
}
// Tampilkan slider CAPTCHA.
public void doShow() {
Log.d(TAG, "captcha show");
TTCaptcha.TTOption option = new TTCaptcha.TTOption();
// option.customUri = "file:///android_asset/ali-tt-captcha-demo.html";
option.language = "cn";
option.cancelable = false;
TTCaptcha captcha = TigerTallyAPI.cptCreate(this, option, new TTCaptcha.TTListener() {
@Override
public void success(TTCaptcha captcha, String data) {
Log.d(TAG, "captcha check success:" + data);
}
@Override
public void failed(TTCaptcha captcha, String code) {
Log.d(TAG, "captcha check failed:" + code);
}
});
captcha.show();
}
// Kirim permintaan POST dengan header wToken dan whash opsional.
public static void doPost(String url, String host, String whash, String wtoken, String body, Callback callback) {
Log.d(TAG, "start request post");
int responseCode = 0;
String responseBody = "";
StringBuilder responseCookie = new StringBuilder();
try {
Request.Builder builder = new Request.Builder()
.url(url)
.addHeader("wToken", wtoken) // Wajib: token tanda tangan WAF
.addHeader("Host", host)
.post(RequestBody.create(MediaType.parse("text/x-markdown"), body.getBytes()));
if (whash != null) {
builder.addHeader("ali_sign_whash", whash); // Wajib untuk penandatanganan kustom
}
Response response = okHttpClient.newCall(builder.build()).execute();
responseCode = response.code();
responseBody = response.body() == null ? "" : response.body().string();
for (String item : response.headers("Set-Cookie")) {
responseCookie.append(item).append(";");
}
Log.d(TAG, "response code:" + responseCode);
Log.d(TAG, "response cookie:" + responseCookie);
Log.d(TAG, "response body:" + (responseBody.length() > 100 ? responseBody.substring(0, 100) : ""));
if (response.isSuccessful()) {
Log.d(TAG, "success: " + response.code() + ", " + response.message());
} else {
Log.e(TAG, "failed: " + response.code() + ", " + response.message());
}
response.close();
} catch (Exception e) {
e.printStackTrace();
responseCode = -1;
responseBody = e.toString();
} finally {
if (callback != null) {
callback.onResponse(responseCode, responseCookie.toString(), responseBody);
}
}
}
public interface Callback {
void onResponse(int code, String cookie, String body);
}
}Setelah SDK diintegrasikan, SDK secara otomatis:
Menandatangani setiap permintaan keluar dengan header
wTokenuntuk diverifikasi oleh WAF.Secara opsional melampirkan header
ali_sign_whashuntuk skenario penandatanganan kustom.Memungkinkan aplikasi Anda mendeteksi dan merespons tantangan CAPTCHA WAF.