Turnstile は訪問者のブラウザーで JavaScript チャレンジを実行するため、ブラウザー環境が必要です。モバイルデバイスでは、追加設定なしでモバイルブラウザー上で動作します。
ネイティブモバイルアプリでは、Turnstile はネイティブには動作しません。代わりに、ネイティブアプリに埋め込んだブラウザーコンポーネントである WebView を使い、Turnstile ウィジェットを含むウェブページを読み込みます。
WebView はネイティブアプリ内にブラウザーエンジンを埋め込みます。ウェブページ、フォーム、Turnstile ウィジェットのような JavaScript コンテンツを表示できます。
WebView で Turnstile を正しく動作させるには、次の要件を満たす必要があります。
- JavaScript の実行を有効にする必要があります。
- DOM Storage API が利用できる必要があります。
- 標準の Web API にアクセスできる必要があります。
challenges.cloudflare.comへのアクセス- HTTP と HTTPS の両方の接続をサポートすること
about:blankとabout:srcdocへの接続を許可すること
- セッション全体で User Agent を一定に保つこと
- デバイスとブラウザーの特性が安定していること
- コアのブラウザー動作を変更しないこと
WebView webView = findViewById(R.id.webview);
WebSettings webSettings = webView.getSettings();
// Required: Enable JavaScript
webSettings.setJavaScriptEnabled(true);
// Required: Enable DOM storage
webSettings.setDomStorageEnabled(true);
// Recommended: Enable other web features
webSettings.setLoadWithOverviewMode(true);
webSettings.setUseWideViewPort(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowContentAccess(true);
// Load your web content with Turnstile
webView.loadUrl("https://yoursite.com/protected-form");import WebKit
class ViewController: UIViewController {
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Configure WebView
let configuration = WKWebViewConfiguration()
configuration.preferences.javaScriptEnabled = true
// Load your web content with Turnstile
if let url = URL(string: "https://yoursite.com/protected-form") {
webView.load(URLRequest(url: url))
}
}
}import { WebView } from "react-native-webview";
export default function App() {
return (
<WebView
source={{ uri: "https://yoursite.com/protected-form" }}
javaScriptEnabled={true}
domStorageEnabled={true}
allowsInlineMediaPlayback={true}
mediaPlaybackRequiresUserAction={false}
/>
);
}import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class WebViewScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse('https://yoursite.com/protected-form')
),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
javaScriptEnabled: true,
useShouldOverrideUrlLoading: false,
),
android: AndroidInAppWebViewOptions(
domStorageEnabled: true,
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
),
),
);
}
}セッション中に User Agent を変更すると、Turnstile のチャレンジは失敗します。訪問者の真正性を検証するため、システムはブラウザー特性の一貫性に依存しています。セッション途中で User Agent が変わると、Turnstile はセキュリティリスクとみなし、チャレンジを拒否します。
// Android - Set consistent User Agent
webSettings.setUserAgentString(webSettings.getUserAgentString());// iOS - Maintain default User Agent
webView.customUserAgent = webView.value(forKey: "userAgent") as? String厳格な Content Security Policy 設定は、Turnstile が必要なスクリプトの読み込みやネットワーク接続を行うのを妨げることがあります。CSP ヘッダーや meta タグが、Turnstile が必要とするドメインとリソースへのアクセスをブロックすると発生します。
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src 'self' challenges.cloudflare.com 'unsafe-inline';
connect-src 'self' challenges.cloudflare.com;
frame-src 'self' challenges.cloudflare.com;
"
/>WebView のセキュリティ制限により、Turnstile の動作に必要なドメインへアクセスできないことがあります。特定ドメインだけを許可する、または一部の接続をブロックする設定の WebView では、チャレンジの読み込みや Cloudflare サーバーとの通信が妨げられます。
解決するには、Turnstile が必要とするすべてのドメインを、WebView の許可オリジンに含めます。
challenges.cloudflare.comabout:blankabout:srcdoc- 自サイトのドメイン
設定方法はプラットフォームごとに異なります。これらのドメインへのネットワークアクセスを明示的に許可するのが原則です。
セッション間で Cookie やローカルストレージが保持されないと、Turnstile は失敗することがあります。状態の維持と訪問者の行動追跡に、これらの仕組みを使うためです。WebView のストレージ設定が厳しすぎる場合や、アプリがセッション間でストレージを消去する場合によく起きます。Cookie とローカルストレージを正しく扱えるよう、WebView を設定します。
// Android - Enable cookies
CookieManager.getInstance().setAcceptCookie(true);
CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);// iOS - Configure cookie storage
webView.configuration.websiteDataStore = WKWebsiteDataStore.default()