我有一个简单的联系表格的网站 . 验证有点微小,因为它不会进入数据库;只是一封电子邮件表格如下:
有5个字段 - 其中4个是必需的 . 提交被禁用,直到4个字段有效,然后您可以提交 . 然后在服务器上再次验证所有内容,包括recaptcha(我的客户端未验证) . 整个过程使用ajax完成,并且有多个测试必须在服务器端传递或返回4 **头,并调用失败回调处理程序 .
一切都像桌面上的Chrome浏览器一样(我没有尝试过其他浏览器,但我无法想象他们为什么会有所不同),但是在iPhone上,即使我没有选中复选框,reCaptcha仍会验证考试 .
换句话说:我仍然需要正确填写四个值才能提交,但如果我没有选中reCaptcha的方框,请求仍然会成功 .
我可以发布一些代码,如果有人认为这将有所帮助,但似乎问题在于设备而不是代码 . 有没有人对此有任何见解?
注意:如果这有用,服务器端是PHP / Apache .
Update: 5/28/2015 :
我还在调试这个,但似乎Mobile Safari忽略了我的iPhone上的响应 Headers . 当我将响应输出到页面时,我在桌面上获得的 (data,status,xhr)
是:
-
data
:我的回答在这一点上只是说错误或成功 - >error
-
status
:error
-
xhr
:{'error',400,'error'}
在移动野生动物园:
-
data
:error
-
status
:success
-
xhr
:{'error',200,'success'}
所以 - 它似乎只是忽略了我的响应头 . 我试着明确设置 {"headers":{"cache-control":"no-cache"}}
但无济于事 .
Update: 6/3/2015
每个请求,这是代码 . 这几乎可以肯定超过你的需要 . 由于我试图修复它所做的改变,它也变得更加迟钝 . 另请注意,虽然可能看起来存在尚未定义的变量,但它们(应该)已在其他文件中定义 .
The client side
$('#submit').on('click', function(e) {
$(this).parents('form').find('input').each(function() {
$(this).trigger('blur');
})
var $btn = $(this);
$btn = $btn.button('loading');
var dfr = $.Deferred();
if ($(this).attr('disabled') || $(this).hasClass('disabled')) {
e.preventDefault();
e.stopImmediatePropagation();
dfr.reject();
return false;
} else {
var input = $('form').serializeArray();
var obj = {},
j;
$.each(input, function(i, a) {
if (a.name === 'person-name') {
obj.name = a.value;
} else if (a.name === 'company-name') {
obj.company_name = a.value;
} else {
j = a.name.replace(/(g-)(.*)(-response)/g, '$2');
obj[j] = a.value;
}
});
obj.action = 'recaptcha-js';
obj.remoteIp = rc.remoteiP;
rc.data = obj;
var request = $.ajax({
url: rc.ajaxurl,
type: 'post',
data: obj,
headers: {
'cache-control': 'no-cache'
}
});
var success = function(data) {
$btn.data('loadingText', 'Success');
$btn.button('reset');
$('#submit').addClass('btn-success').removeClass('btn-default');
$btn.button('loading');
dfr.resolve(data);
};
var fail = function(data) {
var reason = JSON.parse(data.responseText).reason;
$btn.delay(1000).button('reset');
switch (reason) {
case 'Recaptcha Failed':
case 'Recaptcha Not Checked':
case 'One Or more validator fields not valid or not filled out':
case 'One Or more validator fields is invalid':
// reset recaptcha
if ($('#submit').data('tries')) {
$('#submit').remove();
$('.g-recaptcha').parent().addBack().remove();
myPopover('Your request is invalid. Please reload the page to try again.');
} else {
$('#submit').data('tries', 1);
grecaptcha.reset();
myPopover('One or more of your entries are invalid. Please make corrections and try again.');
}
break;
default:
// reset page
$('#submit').remove();
$('.g-recaptcha').remove();
myPopover('There was a problem with your request. Please reload the page and try again.');
break;
}
dfr.reject(data);
};
request.done(success);
request.fail(fail);
}
The Server:
function _send_email(){
$recaptcha=false;
/* * */
if(isset($_POST['recaptcha'])):
$gRecaptchaResponse=$_POST['recaptcha'];
$remoteIp=isset($_POST['remoteIp']) ? $_POST['remoteIp'] : false;
/* ** */
if(!$remoteIp):
$response=array('status_code'=>'409','reason'=>'remoteIP not set');
echo json_encode($response);
http_response_code(409);
exit();
endif;
/* ** */
/* ** */
if($gRecaptchaResponse==''):
$response=array('status_code'=>'400','reason'=>'Recaptcha Failed');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* ** */
if($recaptcha=recaptcha_test($gRecaptchaResponse,$remoteIp)):
$recaptcha=true;
/* ** */
else:
$response=array('status_code'=>'400','reason'=>'Recaptcha Failed');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* ** */
/* * */
else:
$response=array('status_code'=>'400','reason'=>'Recaptcha Not Checked');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* * */
/* * */
if($recaptcha==1):
$name=isset($_POST['name']) ? $_POST['name'] : false;
$company_name=isset($_POST['company_name']) ? $_POST['company_name'] : false;
$phone=isset($_POST['phone']) ? $_POST['phone'] : false;
$email=isset($_POST['email']) ? $_POST['email'] : false;
/* ** */
if(isset($_POST['questions'])):
$questions=$_POST['questions']=='' ? 1 : $_POST['questions'];
/* *** */
if(!$questions=filter_var($questions,FILTER_SANITIZE_SPECIAL_CHARS)):
$response=array('status_code'=>'400','reason'=>'$questions could not be sanitized');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* *** */
/* ** */
else:
$questions=true;
endif;
/* ** */
/* ** */
if( count( array_filter( array( $name,$company_name,$phone,$email ),"filter_false" ) ) !=4 ):
$response=array('status_code'=>'400','reason'=>'One Or more validator fields not valid or not filled out');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* ** */
$company_name=filter_var($company_name,FILTER_SANITIZE_SPECIAL_CHARS);
$name=filter_var($name,FILTER_SANITIZE_SPECIAL_CHARS);
$phone=preg_replace('/[^0-9+-]/', '', $phone);
$email=filter_var($email,FILTER_VALIDATE_EMAIL);
/* ** */
if($company_name && $recaptcha && $name && $phone && $email && $questions):
$phone_str='Phone: ' . $phone;
$company_str='Company: ' . $company_name;
$email_str='Email String: ' . $email;
$name_str='Name: '.$name;
$questions=$questions==1 ? '' : $questions;
$body="$name_str\r\n\r\n$company_str\r\n\r\n$email_str\r\n\r\n$phone_str\r\n\r\n____________________\r\n\r\n$questions";
$mymail='fake@fake.com';
$headers = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-type: text/plain; charset=\"utf-8\"";
$headers[] = "From: $email";
$headers[] = "X-Mailer: PHP/" . phpversion();
/* *** */
if(mail('$mymail', 'Information Request from: ' . $name,$body,implode("\r\n",$headers))):
$response=array('status_code'=>'200','reason'=>'Sent !');
echo json_encode($response);
http_response_code(200);
exit();
/* *** */
else:
$response=array('status_code'=>'400','reason'=>'One Or more validator fields is invalid');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* *** */
endif;
/* ** */
endif;
/* * */
$response=array('status_code'=>'412','reason'=>'There was an unknown error');
echo json_encode($response);
http_response_code(412);
exit();
}
function recaptcha_test($gRecaptchaResponse,$remoteIp){
$secret=$itsasecret; //removed for security;
require TEMPLATE_DIR . '/includes/lib/recaptcha/src/autoload.php';
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
if ($resp->isSuccess()) {
return true;
// verified!
} else {
$errors = $resp->getErrorCodes();
return false;
}
}
4 回答
就像那个问题iOS: Authentication using XMLHttpRequest - Handling 401 reponse最简单的解决方法是忽略自然 Headers 验证,并在回调成功时,用一些标志验证 .
我看过一些这样的案例,从来没有闻到过好的 .
您的“remoteIP”变量是否在客户端正确设置?
即使您的Ajax请求发送空值或假值,php脚本中的isset()函数也将返回true,从而错误地填充$ remoteIp .
尝试做:
Ajax只是让浏览器执行请求,因此PHP可以完美地获取用户的ip .
我敢肯定,如果你传递错误的 Value ,ReCaptcha会以这种或那种方式陷入困境 .
从不信任任何Javascript变量也比Ajax更安全,因为那些也应该被视为用户输入 .
验证码旨在防止恶意客户端(机器人),所以理论上 if a client bypasses the captcha, it is a server side problem. (但是,如果客户端无法完成验证码,则可能是服务器端问题或客户端问题 . )
所以问题必须在服务器上 . 即使出于安全考虑,您应该使用
$_SERVER['REMOTE_ADDR']
而不是$_POST['remoteIp']
,因为$_POST['remoteIp']
可能是伪造的(由恶意客户端) . 事实上,$_SERVER['REMOTE_ADDR']
比客户端$_POST['remoteIp']
更可靠 .我在2或3个月前创建了一个仍然完美的脚本,试试这个:
通常,它应该工作(只需添加你的私钥和你的公钥),我在我的iPhone SE上测试,2秒前,它工作得很好 .