すべてのプロダクト
Search
ドキュメントセンター

Web Application Firewall:iOS app SDK integration

最終更新日:Apr 01, 2026

Web Application Firewall (WAF) のアプリ保護 SDK をご利用の iOS アプリに統合することで、リクエスト署名とボット保護を有効にできます。統合後、WAF はリクエスト署名を検証し、悪意のあるトラフィックを検出してブロックします。

前提条件

開始する前に、以下をご確認ください。

  • iOS 9.0 以降を実行している iOS アプリ (それ以前のバージョンはサポートされていません)

  • iOS 向け WAF アプリ保護 SDK — チケットを起票して、製品技術エキスパートから入手してください

  • SDK 認証キー (AppKey) — ボット管理を有効化した後、[ボット管理] > [アプリ保護] に移動し、アプリ一覧で [AppKey の取得とコピー] をクリックします

image
SDK パッケージ名は tigertally-X.Y.Z-xxxx-ios.zip (X.Y.Z はバージョン番号) で、2 つのフレームワークファイルと 2 つの xcframework ファイルが含まれています。各 Alibaba Cloud アカウントには、WAF で保護されたすべてのドメインに適用される 1 つの AppKey があり、Android、iOS、HarmonyOS の統合で共通して使用できます。

AppKey の例:**OpKLvM6zliu6KopyHIhmneb_u4ekci2W8i6F9vrgpEezqAzEzj2ANrVUhvAXMwYzgY_vc51aEQlRovkRoUhRlVsf4IzO9dZp6nN_Wz8pk2TDLuMo4pVIQvGaxH3vrsnSQiK**

SDK バージョンの選択

iOS SDK には 2 つのバージョンがあります。ご利用のアプリが広告主向け識別子 (IDFA) を使用するかに基づいて選択してください。

バージョンフレームワークファイル使用条件
IDFAAliTigerTally_IDFA.frameworkご利用のアプリが IDFA を使用する場合
Non-IDFAAliTigerTally_NOIDFA.frameworkアプリは IDFA を使用していません

ステップ 1:プロジェクトの作成

Xcode で新しい iOS プロジェクトを作成し、セットアップウィザードを完了します。

image.png

ステップ 2:フレームワークファイルの追加

メインの SDK フレームワークをプロジェクトに追加します。IDFA の要件に合ったバージョンを選択してください。

IDFA バージョン:

image.png

Non-IDFA バージョン:

image.png

CAPTCHA モジュールフレームワーク AliCaptcha.framework をプロジェクトに追加します。

image.png

リソースバンドル AliCaptcha.bundle をプロジェクトに追加します。

image.png

ステップ 3:依存ライブラリの追加

ターゲットのビルドフェーズにある [Link Binary With Libraries] に、以下のライブラリを追加します。

ライブラリIDFA バージョンNon-IDFA バージョン
libc++.tbdはいはい
libresolv.9.tbdはいはい
CoreTelephony.frameworkはいはい
AdSupport.frameworkはいいいえ
AppTrackingTransparency.frameworkはいいいえ
image.png

ステップ 4:リンカーフラグの設定

[ビルド設定] で、-ObjC[その他のリンカフラグ] に追加します:

image.png

ステップ 5:統合コードの追加

ヘッダーファイルのインポート

IDFA バージョン:

#import <AliTigerTally_IDFA/AliTigerTally.h>

Non-IDFA バージョン:

#import <AliTigerTally_NOIDFA/AliTigerTally.h>

SDK の初期化

アプリの起動時に init を一度呼び出して、デバイス情報を収集します。SDK は 3 つのデータ収集モードをサポートしています。プライバシー要件に基づいて 1 つを選択してください。

モードcollectType の値収集内容
フルTT_DEFAULTすべてのデバイスデータ
カスタムプライバシーTT_NO_BASIC_DATATT_NO_UNIQUE_DATATT_NO_EXTRA_DATA (| で組み合わせ可能)部分的なデータ — 指定されたカテゴリを除外
非プライバシーTT_NOT_GRANTEDプライバシー関連フィールドなし (IDFA とベンダー向け識別子 (IDFV) を除外)
完全なデータは脅威検知の精度を向上させます。プライバシーコンプライアンスの要件を満たしつつ、できるだけ多くのデータを収集するモードを選択してください。

データ収集カテゴリのリファレンス:

collectType フラグ除外対象
TT_NO_BASIC_DATAデバイス名、システムバージョン、画面の解像度
TT_NO_UNIQUE_DATAIDFV と IDFA
TT_NO_EXTRA_DATA接続中の Wi-Fi 情報 (SSID、BSSID) および周辺の Wi-Fi ネットワーク

`init` メソッドシグネチャ:

- (int)init:(NSString *)appkey
    collectType:(TTCollectType)type
    options:(NSMutableDictionary *_Nullable)options
    listener:(TTInitListener _Nullable)onInitFinish;

パラメーター:

パラメーター説明
appkeyNSStringボット管理コンソールで取得した AppKey
collectTypeTTCollectTypeデータ収集モード (上記の表をご参照ください)
optionsNSMutableDictionaryレポート構成 (任意、下記の表をご参照ください)。デフォルト:nil
onInitFinishTTInitListener初期化コールバック。デフォルト:nil

`options` の構成:

キー説明
IPv60 (デフォルト)、10:IPv4 を使用します。1:IPv6 を使用します。
Intl0 (デフォルト)、10:中国本土からレポートします。1:中国本土以外からレポートします。
CustomUrlURL 文字列カスタムレポートサーバー URL (特定のリージョン向け、例:https://cloudauth-device.us-west-1.aliyuncs.com)
CustomHostホスト名文字列カスタムレポートサーバーホスト (例:cloudauth-device.us-west-1.aliyuncs.com)
ほとんどの国際リージョンでは、Intl1 に設定してください。米国 (シリコンバレー) など、特定のリージョンにレポートする必要がある場合にのみ、CustomUrlCustomHost を設定します。

戻り値: int — 成功した場合は 0、失敗した場合は負の値を返します。

例:

NSString *appKey = @"<your-appkey>";

NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setValue:@"0" forKey:@"IPv6"];  // IPv4 を使用
[options setValue:@"0" forKey:@"Intl"];  // 中国本土からレポート
// [options setValue:@"1" forKey:@"Intl"];  // 中国本土以外からレポート

// 米国 (シリコンバレー) にレポートする場合:
// [options setValue:@"https://cloudauth-device.us-west-1.aliyuncs.com" forKey:@"CustomUrl"];
// [options setValue:@"cloudauth-device.us-west-1.aliyuncs.com" forKey:@"CustomHost"];

// 全データ収集
if (0 == [[AliTigerTally sharedInstance] init:appKey collectType:TT_DEFAULT options:options listener:nil]) {
    NSLog(@"Initialization successful");
} else {
    NSLog(@"Initialization failed");
}

// カスタムプライバシー:基本および拡張デバイスデータを除外
TTCollectType collectPrivacy = TT_NO_BASIC_DATA | TT_NO_EXTRA_DATA;
[[AliTigerTally sharedInstance] init:appKey collectType:collectPrivacy options:options listener:nil];

// 非プライバシー:すべてのプライバシー関連フィールドを除外
[[AliTigerTally sharedInstance] init:appKey collectType:TT_NOT_GRANTED options:options listener:nil];
重要

init を呼び出した後、vmpSign を呼び出す前に少なくとも 2 秒待機してください。この間隔は推奨事項であり、必須ではありません。SDK の保護効果を向上させることを目的としています。必要に応じてこの間隔を調整できますが、間隔が短いと保護の品質が低下する可能性があります。

ユーザーアカウントの設定 (任意)

setAccount を呼び出して、非識別化されたユーザー識別子をリクエストに関連付けます。これにより、より詳細な WAF 軽減ポリシーが可能になります。

/**
 * ユーザーアカウントを設定します。
 * @param account  ユーザーを識別する非識別化された文字列。
 */
- (void)setAccount:(NSString *)account;

ゲストユーザーの場合は、この呼び出しをスキップして初期化に進みます。ユーザーがログインした後、setAccount を呼び出してから再初期化します。

[[AliTigerTally sharedInstance] setAccount:@"<desensitized-user-id>"];

リクエストへの署名

すべての例では、vmpSign を使用して wtoken 文字列を生成し、それを wToken リクエストヘッダーにアタッチします。

デフォルト署名

コンソールでカスタム署名オプションを選択していない場合は、デフォルト署名を使用します。

リクエストボディを vmpSign に渡します。ボディがないリクエスト (GET など) の場合は、nil または NSData としてエンコードされた空の文字列を渡します。

/**
 * VMP 技術を使用してデータに署名します。
 * @param input  署名するデータ (リクエストボディ、またはボディが空の場合は nil)。
 * @return リクエスト認証用の wtoken 文字列。
 */
- (NSString *)vmpSign:(NSData *)input;

例:

NSString *body = @"hello world";
NSString *wtoken = [[AliTigerTally sharedInstance]
    vmpSign:[body dataUsingEncoding:NSUTF8StringEncoding]];
// wtoken を "wToken" HTTP リクエストヘッダーにアタッチします

カスタム署名

コンソールでカスタム署名オプションを選択した場合は、カスタム署名を使用します。まず vmpHash を呼び出して whash を生成し、その whashvmpSign の入力として渡します。

  • POST、PUT、PATCH リクエストの場合:リクエストボディvmpHash に渡します

  • GET、DELETE リクエストの場合:完全な URLvmpHash に渡します

whash」値を「ali_sign_whash」リクエストヘッダーに追加します。また、コンソールのシナリオベースのポリシー構成で、[カスタム署名フィールド] を「ali_sign_whash」に設定します。

/**
 * カスタム署名のためにデータをハッシュ化します。
 * @param type   HTTP メソッド (TT_GET, TT_POST, TT_PUT, TT_PATCH, TT_DELETE)。
 * @param input  ハッシュ化するデータ (POST/PUT/PATCH の場合はリクエストボディ、GET/DELETE の場合は完全な URL)。
 * @return whash 文字列。
 */
- (NSString *)vmpHash:(TTRequestType)type input:(NSData *)input;

POST リクエストの例:

NSString *body = @"hello world";

// リクエストボディから whash を生成
NSString *whash = [[AliTigerTally sharedInstance]
    vmpHash:TT_POST input:[body dataUsingEncoding:NSUTF8StringEncoding]];

// whash から wtoken を生成
NSString *wtoken = [[AliTigerTally sharedInstance]
    vmpSign:[whash dataUsingEncoding:NSUTF8StringEncoding]];

// whash を "ali_sign_whash" ヘッダーに、wtoken を "wToken" ヘッダーにアタッチ
NSLog(@"whash: %@, wtoken: %@", whash, wtoken);

GET リクエストの例:

NSString *url = @"https://tigertally.aliyun.com/apptest";

// 完全な URL から whash を生成する
NSString *whash = [[AliTigerTally sharedInstance]
    vmpHash:TT_GET input:[url dataUsingEncoding:NSUTF8StringEncoding]];

// whash から wtoken を生成する
NSString *wtoken = [[AliTigerTally sharedInstance]
    vmpSign:[whash dataUsingEncoding:NSUTF8StringEncoding]];
vmpHash に渡される URL は、最終的なリクエスト URL と完全に一致する必要があります。一部のフレームワークは、中国語の文字またはクエリパラメーターを自動的にエンコードします。エンコーディングに違いがないことを確認してください。vmpHash は空の文字列を受け付けません。GET リクエストの場合、URL にはパスまたはクエリパラメーターを含める必要があります。

二次検証の処理

WAF が不審なアクティビティを検出すると、CAPTCHA チャレンジを返します。各レスポンスを確認し、必要に応じて CAPTCHA スライダーを表示します。

レスポンスの確認

すべてのリクエストの後に、レスポンスクッキーとボディを cptCheck に渡します。

/**
 * 二次検証が必要かどうかを確認します。
 * @param cookie  レスポンスからのすべてのクッキー ("key=value;" 形式にマージ)。
 * @param body    完全なレスポンスボディ。
 * @return 0: パス。1: 二次検証が必要。
 */
- (int)cptCheck:(NSString *)cookie body:(NSData *)body;
レスポンスヘッダーには複数の Set-Cookie フィールドが含まれる場合があります。cptCheck に渡す前に、それらを key1=value1;key2=value2; のフォーマットにマージしてください。

例:

NSString *cookie = @"key1=value1;key2=value2;";
NSData *body = /* response body */;
int recheck = [[AliTigerTally sharedInstance] cptCheck:cookie body:body];
// recheck == 1: CAPTCHA スライダーを表示

CAPTCHA スライダーの表示

cptCheck1 を返した場合、TTCaptcha スライダーを作成して表示します。

/**
 * 二次検証用の CAPTCHA スライダーを作成します。
 * @param view      親ビュー。
 * @param option    スライダー構成。
 * @param delegate  検証結果のコールバック。
 * @return TTCaptcha スライダーオブジェクト。
 */
- (TTCaptcha *)cptCreate:(UIView *)view option:(TTOption *)option delegate:(id<TTDelegate>)delegate;

`TTOption` の構成:

プロパティ説明
cancelableBOOLユーザーがスライダーの外側をタップして閉じられるようにします
customUriNSStringカスタム検証ページへのパス (ローカル HTML ファイルまたはリモート URL)
languageNSString表示言語 (例:中国語の場合は @"cn"、英語の場合は @"en")

`TTDelegate` コールバック:

@protocol TTDelegate <NSObject>
@required
// 検証が成功したときに呼び出されます。
- (void)success:(TTCaptcha *)captcha data:(NSString *)data;

// 検証が失敗したときに呼び出されます。
- (void)failed:(TTCaptcha *)captcha code:(NSString *)code;
@end

例:

TTOption *option = [[TTOption alloc] init];
option.language   = @"cn";
option.cancelable = YES;

TTCaptcha *captcha = [[AliTigerTally sharedInstance]
    cptCreate:[self view] option:option delegate:self];
[captcha show];

// TTDelegate コールバック内:
- (void)success:(TTCaptcha *)captcha data:(nonnull NSString *)data {
    NSLog(@"Verification passed: %@", data);
}

- (void)failed:(TTCaptcha *)captcha code:(nonnull NSString *)code {
    NSLog(@"Verification failed with code: %@", code);
}

初期化ステータスコード

コード定数説明
0TT_SUCCESS初期化に成功しました
-1TT_NOT_INITinit が呼び出されていません
-2TT_NOT_PERMISSION必要な iOS 権限が付与されていません
-3TT_UNKNOWN_ERROR不明なシステムエラー
-4TT_NETWORK_ERRORネットワークエラー
-5TT_NETWORK_ERROR_EMPTYネットワークエラー — レスポンスボディが空です
-6TT_NETWORK_ERROR_INVALIDネットワークエラー — レスポンスのフォーマットが無効です
-7TT_PARSE_SRV_CFG_ERRORサーバー構成の解析に失敗しました
-8TT_NETWORK_RET_CODE_ERRORゲートウェイが失敗のレスポンスを返しました
-9TT_APPKEY_EMPTYAppKey が空です
-10TT_PARAMS_ERRORパラメーターエラー
-11TT_FGKEY_ERRORキー計算エラー
-12TT_APPKEY_ERRORSDK バージョンが AppKey バージョンと一致しません

CAPTCHA エラーコード

コード説明
1001検証に失敗しました (ユーザー操作中または操作後のスライダー例外)
1002システム例外
1003パラメーターエラー
1005ユーザーによって検証がキャンセルされました
8001スライダーの呼び出しに失敗しました
8002スライダー検証データが異常です
8003スライダー検証中の内部例外
8004ネットワークエラー

トラブルシューティング

`vmpSign` または `vmpHash` がトークンではなくエラー文字列を返す

whash または wtoken に以下のいずれかの文字列が含まれている場合、エラーが発生しています。

  • "you must call init first"init が署名の前に呼び出されていません。init を呼び出し、vmpSign を呼び出す前に少なくとも 2 秒待機してください。

  • "you must input correct data" — 入力データが無効です。リクエストボディまたは URL が空でないか、不正な形式でないかを確認してください。

  • "you must input correct type"vmpHash に渡された HTTP メソッドタイプが正しくありません。

GET リクエスト署名における URL エンコーディングの不一致

GET リクエストの whash が拒否された場合、vmpHash に渡された URL が実際のリクエスト URL と一致していない可能性があります。一部のネットワークフレームワークは、クエリパラメーターや漢字を自動的にパーセントエンコーディングします。両方の URL をログに出力し、文字ごとに比較してください。

初期化が `TT_NETWORK_ERROR` (`-4`) で失敗する

デバイスがネットワークにアクセスでき、レポートドメインに到達可能であることを確認してください。中国本土以外でデプロイする場合は、options ディクショナリで Intl1 に設定します。特定のリージョンエンドポイントについては、CustomUrlCustomHost を設定してください。

完全な例

以下の例は、初期化、リクエスト署名、二次検証の確認、CAPTCHA 表示までの完全な統合フローを示しています。

#import "DemoController.h"
#if __has_include(<AliTigerTally_NOIDFA/AliTigerTally_NOIDFA.h>)
    #import <AliTigerTally_NOIDFA/AliTigerTally_NOIDFA.h>
#else
    #import <AliTigerTally_IDFA/AliTigerTally_IDFA.h>
#endif

@interface DemoController () <TTDelegate>
@end

static NSString *kAppHost = @"******";
static NSString *kAppUrl  = @"******";
static NSString *kAppkey  = @"******";

@implementation DemoController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self doTest];
}

- (void)doTest {
    NSThread *thread = [[NSThread alloc] initWithBlock:^{
        // ステップ 1:SDK の初期化
        NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
        // [options setValue:@"1" forKey:@"Intl"];  // 中国本土以外の場合はコメントを解除します
        int code = [[AliTigerTally sharedInstance] init:kAppkey collectType:TT_DEFAULT options:options listener:nil];
        NSLog(@"tigertally init: %d", code);

        // ステップ 2:署名する前に少なくとも 2 秒待機します
        [NSThread sleepForTimeInterval:2.0];

        // ステップ 3:リクエストへの署名 (カスタム署名の例)
        NSString *body = @"hello world";
        NSString *whash = [[AliTigerTally sharedInstance]
            vmpHash:TT_POST input:[body dataUsingEncoding:NSUTF8StringEncoding]];
        NSString *wtoken = [[AliTigerTally sharedInstance]
            vmpSign:[whash dataUsingEncoding:NSUTF8StringEncoding]];
        NSLog(@"tigertally vmp — whash: %@, wtoken: %@", whash, wtoken);

        // デフォルト署名の場合 (カスタム署名オプションが選択されていない場合):
        // wtoken = [[AliTigerTally sharedInstance] vmpSign:[body dataUsingEncoding:NSUTF8StringEncoding]];

        // ステップ 4:リクエストを送信し、二次検証を確認します
        [self doPost:kAppUrl host:kAppHost whash:whash wtoken:wtoken
            body:[body dataUsingEncoding:NSUTF8StringEncoding]
            callback:^(NSInteger code, NSString *cookie, NSData *body) {
                int check = [[AliTigerTally sharedInstance] cptCheck:cookie body:body];
                NSLog(@"captcha check result: %d", check);
                if (check == 0) return;
                // 二次検証が必要 — メインスレッドで CAPTCHA を表示します
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    [self doShow];
                }];
            }];
    }];
    [thread start];
}

- (void)doShow {
    TTOption *option = [[TTOption alloc] init];
    option.language   = @"cn";
    option.cancelable = YES;
    TTCaptcha *captcha = [[AliTigerTally sharedInstance]
        cptCreate:[self view] option:option delegate:self];
    [captcha show];
}

- (void)doPost:(NSString *)url host:(NSString *)host
        whash:(NSString *)whash wtoken:(NSString *)wtoken
        body:(NSData *)body callback:(void(^)(NSInteger code, NSString *cookie, NSData *body))callback {
    NSURL *requestUrl = [NSURL URLWithString:url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl
        cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
    [request setValue:@"text/x-markdown" forHTTPHeaderField:@"Content-Type"];
    [request setValue:host forHTTPHeaderField:@"HOST"];
    [request setValue:wtoken forHTTPHeaderField:@"wToken"];
    if (whash) {
        [request setValue:whash forHTTPHeaderField:@"ali_sign_whash"];
    }
    request.HTTPMethod = @"POST";
    request.HTTPBody = body;

    NSURLSessionDataTask *dataTask = [[NSURLSession sharedSession]
        dataTaskWithRequest:request
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (error) {
                callback(-1, nil, [[error description] dataUsingEncoding:NSUTF8StringEncoding]);
                return;
            }
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            NSMutableString *cookies = [[NSMutableString alloc] init];
            for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
                if ([url containsString:[cookie domain]]) {
                    [cookies appendFormat:@"%@=%@;", [cookie name], [cookie value]];
                }
            }
            callback(httpResponse.statusCode, cookies, data);
        }];
    [dataTask resume];
}

#pragma mark - TTDelegate

- (void)failed:(TTCaptcha *)captcha code:(nonnull NSString *)code {
    NSLog(@"captcha failed: %@", code);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
        message:code preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
    [self presentViewController:alert animated:YES completion:nil];
}

- (void)success:(TTCaptcha *)captcha data:(nonnull NSString *)data {
    NSLog(@"captcha success: %@", data);
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
        message:data preferredStyle:UIAlertControllerStyleAlert];
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
    [self presentViewController:alert animated:YES completion:nil];
}

@end