为什么 Google ReCaptcha API 允许错误的密钥 and/or 错误的用户令牌响应?

Why does Google ReCaptcha API allow bad secret key and/or bad user token response?

看看下面的代码。这是服务器端。如您所见,我用错误的密钥和错误的用户令牌响应调用 Google ReCaptcha API。你知道吗?有用!更准确地说:Google ReCaptcha API 没有异常回答( 即: 我的 catch 未达到)。为什么?这不是预期的行为,对吗?

/**
 * Verifies a Recaptcha filled by the user in his Android app.
 * 1. Success: returns the JSON response
 * 2. Failure: throws the error
 **/
exports.verifyRecaptcha = functions.https.onCall((data, context) => {

    const user_response_token = data.userResponseToken;
    if(user_response_token === null || user_response_token === '') {
        throw new functions.https.HttpsError('invalid-argument', 'The function must be called with an adequat user response token.');
    }

    const remote_url = 'https://recaptcha.google.com/recaptcha/api/siteverify';
    const secret = '<MY_REAL_SECRET_KEY>';  // Original value: 'https://www.google.com/recaptcha/api/siteverify';  #  Moises' value: https://recaptcha.google.com/recaptcha/api/siteverify

    var options = {
        method: 'POST',
        uri: remote_url,
        body: {secret: 'Foo', response: 'Bar'},
        // body: {secret: secret, response: user_response_token},
        json: true
    };

    return rp(options)
            .then(parsedBody => {
                return {code: 'Success', message: 'You are actually a human (this msg is for test purposes).'};
            })
            .catch(error => {
                throw new functions.https.HttpsError('unknown', error);
            });
});

下面是 Android 应用程序代码:

final SafetyNetApi.RecaptchaTokenResponse response = task.getResult();
assert response != null;
final String userResponseToken = response.getTokenResult();
if (!userResponseToken.isEmpty()) {
    final HashMap<String, String> the_data = new HashMap<>();
    the_data.put("userResponseToken", userResponseToken);
    FirebaseFunctions.getInstance()
            .getHttpsCallable("verifyRecaptcha")
            .call(the_data)
            .continueWith(new Continuation<HttpsCallableResult, Void>() {
                @Override
                public Void then(@NonNull final Task<HttpsCallableResult> task) {
                    if(context.isDestroyed() || context.isFinishing()) {
                        return null;
                    }

                    if(!task.isSuccessful()) {
                        Exception e = task.getException();
                        if (e instanceof FirebaseFunctionsException) {
                            FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
                            System.out.println(ffe.getMessage());
                        }

                        return null;
                    }

                    callback.onAsking();
                    return null;
                }
            });
} else {
    callback.onFailureUserResponseTokenIsEmpty();
}

docs提示invalid-input-secret/invalid-input-response等错误会出现在响应的error-codes字段中。

此信息不一定需要转换为 HTTP 错误代码(这会导致您的 catch 块执行);在这种情况下,Google 显然想要支持多个同时出现的错误消息,并且 HTTP 响应代码更多地与协议在 HTTP 级别的行为有关。

在我们查看文档时,我应该指出,在假定您的用户是人类之前,您可能想参考 success 字段。